From 779c6b6cb8f5db7d862723701b0d4dc01c7712c3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 31 Jan 2017 01:10:54 +0200 Subject: [PATCH 01/21] Add Rvalue::Discriminant to retrieve discriminant --- src/librustc/mir/mod.rs | 7 ++++ src/librustc/mir/tcx.rs | 32 ++++++++++++------- src/librustc/mir/visit.rs | 4 +++ .../borrowck/mir/gather_moves.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 8 +++++ src/librustc_passes/mir_stats.rs | 1 + src/librustc_trans/mir/rvalue.rs | 19 +++++++++++ 7 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index cbb7b2710f5..a3580352261 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -997,6 +997,12 @@ pub enum Rvalue<'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 Box(Ty<'tcx>), @@ -1111,6 +1117,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) } UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), + Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval), Box(ref t) => write!(fmt, "Box({:?})", t), InlineAsm { ref asm, ref outputs, ref inputs } => { write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f1268521d67..68fbadd5d60 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -135,15 +135,15 @@ impl<'tcx> Lvalue<'tcx> { impl<'tcx> Rvalue<'tcx> { pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option> { - match self { - &Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)), - &Rvalue::Repeat(ref operand, ref count) => { + match *self { + Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)), + Rvalue::Repeat(ref operand, ref count) => { let op_ty = operand.ty(mir, tcx); let count = count.value.as_u64(tcx.sess.target.uint_type); assert_eq!(count as usize as u64, count); 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); Some(tcx.mk_ref(reg, ty::TypeAndMut { @@ -152,27 +152,35 @@ impl<'tcx> Rvalue<'tcx> { } )) } - &Rvalue::Len(..) => Some(tcx.types.usize), - &Rvalue::Cast(.., ty) => Some(ty), - &Rvalue::BinaryOp(op, ref lhs, ref rhs) => { + Rvalue::Len(..) => Some(tcx.types.usize), + Rvalue::Cast(.., ty) => Some(ty), + Rvalue::BinaryOp(op, ref lhs, ref rhs) => { let lhs_ty = lhs.ty(mir, tcx); let rhs_ty = rhs.ty(mir, tcx); 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 rhs_ty = rhs.ty(mir, tcx); let ty = op.ty(tcx, lhs_ty, rhs_ty); let ty = tcx.intern_tup(&[ty, tcx.types.bool], false); Some(ty) } - &Rvalue::UnaryOp(_, ref operand) => { + Rvalue::UnaryOp(_, ref operand) => { Some(operand.ty(mir, tcx)) } - &Rvalue::Box(t) => { + Rvalue::Discriminant(ref lval) => { + if let ty::TyAdt(_, _) = lval.ty(mir, tcx).to_ty(tcx).sty { + // TODO + None + } else { + None + } + } + Rvalue::Box(t) => { Some(tcx.mk_box(t)) } - &Rvalue::Aggregate(ref ak, ref ops) => { + Rvalue::Aggregate(ref ak, ref ops) => { match *ak { AggregateKind::Array => { if let Some(operand) = ops.get(0) { @@ -196,7 +204,7 @@ impl<'tcx> Rvalue<'tcx> { } } } - &Rvalue::InlineAsm { .. } => None + Rvalue::InlineAsm { .. } => None } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index b5da304a109..921b4e78b32 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -506,6 +506,10 @@ macro_rules! make_mir_visitor { self.visit_operand(op, location); } + Rvalue::Discriminant(ref $($mutability)* lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Inspect, location); + } + Rvalue::Box(ref $($mutability)* ty) => { self.visit_ty(ty); } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 7cf6ab2999c..806395c857a 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -435,6 +435,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } } Rvalue::Ref(..) | + Rvalue::Discriminant(..) | Rvalue::Len(..) | Rvalue::InlineAsm { .. } => {} Rvalue::Box(..) => { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9c1107344f2..16371be576b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -739,6 +739,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(_) => { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index cec1c20519b..e29febdb712 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -186,6 +186,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { Rvalue::BinaryOp(..) => "Rvalue::BinaryOp", Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp", Rvalue::UnaryOp(..) => "Rvalue::UnaryOp", + Rvalue::Discriminant(..) => "Rvalue::Discriminant", Rvalue::Box(..) => "Rvalue::Box", Rvalue::Aggregate(ref kind, ref _operands) => { // AggregateKind is not distinguished by visit API, so diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 0a8e676b078..fe11e0426df 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -433,6 +433,24 @@ 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); + // FIXME: inline this + let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, None, true); + let discr = if common::val_ty(discr) == Type::i1(bcx.ccx) { + bcx.zext(discr, discr_type) + } else { + bcx.trunc(discr, discr_type) + }; + (bcx, OperandRef { + val: OperandValue::Immediate(discr), + ty: discr_ty + }) + } + mir::Rvalue::Box(content_ty) => { let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); let llty = type_of::type_of(bcx.ccx, content_ty); @@ -661,6 +679,7 @@ pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { mir::Rvalue::BinaryOp(..) | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | mir::Rvalue::Box(..) | mir::Rvalue::Use(..) => true, From 98d1db7fe36fe5454937f40d9fcb4fe97f36bbeb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 31 Jan 2017 05:32:08 +0200 Subject: [PATCH 02/21] If is now always a SwitchInt in MIR --- src/librustc/mir/mod.rs | 12 +----- src/librustc/mir/visit.rs | 11 +----- .../borrowck/mir/dataflow/mod.rs | 4 -- .../borrowck/mir/elaborate_drops.rs | 9 +++-- .../borrowck/mir/gather_moves.rs | 1 - src/librustc_mir/build/expr/into.rs | 37 ++++++++++++------- src/librustc_mir/build/matches/mod.rs | 9 +++-- src/librustc_mir/build/matches/test.rs | 35 +++++++++++------- src/librustc_mir/hair/mod.rs | 3 +- src/librustc_mir/transform/no_landing_pads.rs | 1 - src/librustc_mir/transform/qualify_consts.rs | 1 - src/librustc_mir/transform/simplify.rs | 1 - .../transform/simplify_branches.rs | 22 +++++------ src/librustc_mir/transform/type_check.rs | 16 +------- src/librustc_passes/mir_stats.rs | 1 - src/librustc_trans/mir/analyze.rs | 1 - src/librustc_trans/mir/block.rs | 13 +------ src/test/ui/custom-derive/issue-36935.rs | 1 + 18 files changed, 76 insertions(+), 102 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a3580352261..fa7ba3e6a62 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -453,12 +453,6 @@ pub enum TerminatorKind<'tcx> { 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>, @@ -470,7 +464,7 @@ pub enum TerminatorKind<'tcx> { /// to one of the targets, and otherwise fallback to `otherwise` SwitchInt { /// discriminant value being tested - discr: Lvalue<'tcx>, + discr: Operand<'tcx>, /// type of value being tested switch_ty: Ty<'tcx>, @@ -550,7 +544,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { 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(), Resume => (&[]).into_cow(), @@ -580,7 +573,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { 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(), Resume => Vec::new(), @@ -659,7 +651,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { 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), Return => write!(fmt, "return"), @@ -710,7 +701,6 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Unreachable => vec![], Goto { .. } => vec!["".into()], - If { .. } => vec!["true".into(), "false".into()], Switch { ref adt_def, .. } => { adt_def.variants .iter() diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 921b4e78b32..1e27a02287f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -14,7 +14,6 @@ use ty::subst::Substs; use ty::{ClosureSubsts, Region, Ty}; use mir::*; use rustc_const_math::ConstUsize; -use rustc_data_structures::tuple_slice::TupleSlice; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; @@ -363,14 +362,6 @@ macro_rules! make_mir_visitor { 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 } => { @@ -384,7 +375,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* switch_ty, ref $($mutability)* values, ref targets } => { - self.visit_lvalue(discr, LvalueContext::Inspect, source_location); + self.visit_operand(discr, source_location); self.visit_ty(switch_ty); for value in values { self.visit_const_val(value, source_location); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index f11cf90834d..8dd591fa2e7 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -454,10 +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, 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, .. } => { for target in targets { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index d2f744bde2d..45f534767e4 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -813,9 +813,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { (true, false) => on_set, (true, true) => { let flag = self.drop_flag(c.path).unwrap(); - self.new_block(c, is_cleanup, TerminatorKind::If { - cond: Operand::Consume(flag), - targets: (on_set, on_unset) + let boolty = self.tcx.types.bool; + self.new_block(c, is_cleanup, TerminatorKind::SwitchInt { + discr: Operand::Consume(flag), + switch_ty: boolty, + values: vec![ConstVal::Bool(true)], + targets: vec![on_set, on_unset], }) } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 806395c857a..9e7e5ec9ee8 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -464,7 +464,6 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { self.gather_move(loc, &Lvalue::Local(RETURN_POINTER)); } - TerminatorKind::If { .. } | TerminatorKind::Assert { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Switch { .. } => { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 3d4af259ec9..2b4336ba66f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -15,6 +15,7 @@ use build::expr::category::{Category, RvalueFunc}; use hair::*; use rustc::ty; use rustc::mir::*; +use rustc::middle::const_val::ConstVal; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which @@ -69,9 +70,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); - this.cfg.terminate(block, source_info, TerminatorKind::If { - cond: operand, - targets: (then_block, else_block) + this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: operand, + switch_ty: this.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![then_block, else_block], }); unpack!(then_block = this.into(destination, then_block, then_expr)); @@ -111,16 +114,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs = unpack!(block = this.as_operand(block, lhs)); let blocks = match op { - LogicalOp::And => (else_block, false_block), - LogicalOp::Or => (true_block, else_block), + LogicalOp::And => vec![else_block, false_block], + LogicalOp::Or => vec![true_block, else_block], }; - this.cfg.terminate(block, source_info, - TerminatorKind::If { cond: lhs, targets: blocks }); + this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: lhs, + switch_ty: this.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: blocks, + }); let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); - this.cfg.terminate(else_block, source_info, TerminatorKind::If { - cond: rhs, - targets: (true_block, false_block) + this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt { + discr: rhs, + switch_ty: this.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![true_block, false_block], }); this.cfg.push_assign_constant( @@ -180,9 +189,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { loop_block_end = this.as_operand(loop_block, cond_expr)); body_block = this.cfg.start_new_block(); this.cfg.terminate(loop_block_end, source_info, - TerminatorKind::If { - cond: cond, - targets: (body_block, exit_block) + TerminatorKind::SwitchInt { + discr: cond, + switch_ty: this.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![body_block, exit_block], }); // if the test is false, there's no `break` to assign `destination`, so diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 5c3d93ffda9..0898d06d2e4 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -672,9 +672,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(guard.span); let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, - TerminatorKind::If { cond: cond, - targets: (arm_block, otherwise)}); + self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: cond, + switch_ty: self.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![arm_block, otherwise], + }); Some(otherwise) } else { let source_info = self.source_info(candidate.span); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index a35b2925ae2..291bd65d577 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -221,10 +221,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; - (targets, - TerminatorKind::If { - cond: Operand::Consume(lvalue.clone()), - targets: (true_bb, else_bb) + (targets, TerminatorKind::SwitchInt { + discr: Operand::Consume(lvalue.clone()), + switch_ty: self.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![true_bb, else_bb] }) } @@ -240,7 +241,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (targets.clone(), TerminatorKind::SwitchInt { - discr: lvalue.clone(), + discr: Operand::Consume(lvalue.clone()), switch_ty: switch_ty, values: options.clone(), targets: targets @@ -314,9 +315,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // check the result let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, source_info, TerminatorKind::If { - cond: Operand::Consume(eq_result), - targets: (block, fail), + self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt { + discr: Operand::Consume(eq_result), + switch_ty: self.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![block, fail], }); vec![block, fail] @@ -362,9 +365,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch based on result let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), self.cfg.start_new_block()]; - self.cfg.terminate(block, source_info, TerminatorKind::If { - cond: Operand::Consume(result), - targets: (target_blocks[0], target_blocks[1]) + self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: Operand::Consume(result), + switch_ty: self.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: target_blocks.clone(), }); target_blocks @@ -389,9 +394,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch based on result let target_block = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, TerminatorKind::If { - cond: Operand::Consume(result), - targets: (target_block, fail_block) + self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: Operand::Consume(result), + switch_ty: self.hir.bool_ty(), + values: vec![ConstVal::Bool(true)], + targets: vec![target_block, fail_block] }); target_block diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 01dc01c5ecf..4ac67cfb2fc 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -134,7 +134,8 @@ pub enum ExprKind<'tcx> { op: LogicalOp, lhs: ExprRef<'tcx>, rhs: ExprRef<'tcx>, - }, + }, // NOT overloaded! + // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. Unary { op: UnOp, arg: ExprRef<'tcx>, diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 6ef5720b330..425df65659c 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -28,7 +28,6 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::Unreachable | - TerminatorKind::If { .. } | TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => { /* nothing to do */ diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 16371be576b..bda4c94625f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -394,7 +394,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return Qualif::empty(); } - TerminatorKind::If {..} | TerminatorKind::Switch {..} | TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index d5fc90289e2..1127f50fe50 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -209,7 +209,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { // turn a branch with all successors identical to a goto fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { match terminator.kind { - TerminatorKind::If { .. } | TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => {}, _ => return false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 8759a340d7e..424250586b1 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -30,17 +30,17 @@ impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> { for block in mir.basic_blocks_mut() { let terminator = block.terminator_mut(); terminator.kind = match terminator.kind { - TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { - literal: Literal::Value { - value: ConstVal::Bool(cond) - }, .. - }) } => { - if cond { - TerminatorKind::Goto { target: targets.0 } - } else { - TerminatorKind::Goto { target: targets.1 } - } - } + // TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { + // literal: Literal::Value { + // value: ConstVal::Bool(cond) + // }, .. + // }) } => { + // if cond { + // TerminatorKind::Goto { target: targets.0 } + // } else { + // TerminatorKind::Goto { target: targets.1 } + // } + // } TerminatorKind::Assert { target, cond: Operand::Constant(Constant { literal: Literal::Value { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 529fe564af0..9d2ad314386 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -423,18 +423,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { 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, .. } => { - 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) { span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}", switch_ty, discr_ty, terr); @@ -603,10 +593,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match block.terminator().kind { TerminatorKind::Goto { target } => 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, .. } => { for target in targets { diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index e29febdb712..fef61128d04 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -148,7 +148,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record("TerminatorKind", kind); self.record(match *kind { TerminatorKind::Goto { .. } => "TerminatorKind::Goto", - TerminatorKind::If { .. } => "TerminatorKind::If", TerminatorKind::Switch { .. } => "TerminatorKind::Switch", TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", TerminatorKind::Resume => "TerminatorKind::Resume", diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2a1ab10d74e..97118a72062 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -204,7 +204,6 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { /* nothing to do */ diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index f04f7ab9ed1..b22c16a2955 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -136,14 +136,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { 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()); @@ -180,10 +172,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { + // TODO: cond_br if only 1 value let (otherwise, targets) = targets.split_last().unwrap(); - let lv = self.trans_lvalue(&bcx, discr); - let discr = bcx.load(lv.llval, lv.alignment.to_align()); - let discr = base::to_immediate(&bcx, discr, switch_ty); + let discr = self.trans_operand(&bcx, discr).immediate(); let switch = bcx.switch(discr, llblock(self, *otherwise), values.len()); for (value, target) in values.iter().zip(targets) { let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty); diff --git a/src/test/ui/custom-derive/issue-36935.rs b/src/test/ui/custom-derive/issue-36935.rs index 22d603563de..2231c3c2422 100644 --- a/src/test/ui/custom-derive/issue-36935.rs +++ b/src/test/ui/custom-derive/issue-36935.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:plugin.rs +// ignore-stage1 #![feature(proc_macro)] From 24c93efbb58f6644a62c231916144cc0af55a503 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 1 Feb 2017 03:38:28 +0200 Subject: [PATCH 03/21] Move type of discriminant to AdtDef Previously AdtDef variants contained ConstInt for each discriminant, which did not really reflect the actual type of the discriminants. Moving the type into AdtDef allows to easily put the type into metadata and also saves bytes from ConstVal overhead for each discriminant. Also arguably the code is cleaner now :) --- src/librustc/ty/context.rs | 4 +- src/librustc/ty/layout.rs | 13 +-- src/librustc/ty/mod.rs | 8 +- src/librustc/ty/util.rs | 61 +++---------- src/librustc_metadata/decoder.rs | 16 ++-- src/librustc_metadata/encoder.rs | 10 +-- src/librustc_metadata/schema.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/disr.rs | 2 +- src/librustc_typeck/collect.rs | 107 ++++++++++++----------- 10 files changed, 104 insertions(+), 121 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6203679a510..19bb8a63aa2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -673,10 +673,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn alloc_adt_def(self, did: DefId, kind: AdtKind, + discr_ty: Option, variants: Vec, repr: ReprOptions) -> &'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) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3a463e981a6..4d3a17e51c1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; -use rustc_const_math::ConstInt; use std::cmp; use std::fmt; @@ -1183,10 +1182,12 @@ impl<'a, 'gcx, 'tcx> Layout { i64::min_value(), true); for v in &def.variants { - let x = match v.disr_val.erase_type() { - ConstInt::InferSigned(i) => i as i64, - ConstInt::Infer(i) => i as u64 as i64, - _ => bug!() + let x = match def.discr_ty { + attr::IntType::SignedInt(IntTy::I128) | + attr::IntType::UnsignedInt(UintTy::U128) => + bug!("128-bit discriminants not yet supported"), + attr::IntType::SignedInt(_) => v.disr_val as i64, + attr::IntType::UnsignedInt(_) => v.disr_val as u64 as i64, }; if x == 0 { non_zero = false; } if x < min { min = x; } @@ -1247,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> Layout { // non-empty body, explicit discriminants should have // been rejected by a checker before this point. 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", tcx.item_path_str(def.did)); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index beb286108a0..5ec27b57c37 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -45,7 +45,6 @@ use syntax::attr; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; -use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use hir; @@ -72,6 +71,8 @@ pub use self::context::{Lift, TypeckTables}; pub use self::trait_def::{TraitDef, TraitFlags}; +use rustc_i128::u128; + pub mod adjustment; pub mod cast; pub mod error; @@ -96,7 +97,7 @@ mod flags; mod structural_impls; mod sty; -pub type Disr = ConstInt; +pub type Disr = u128; // Data types @@ -1325,6 +1326,7 @@ pub struct FieldDef { /// table. pub struct AdtDef { pub did: DefId, + pub discr_ty: attr::IntType, // Type of the discriminant pub variants: Vec, destructor: Cell>, flags: Cell, @@ -1387,6 +1389,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, did: DefId, kind: AdtKind, + discr_ty: attr::IntType, variants: Vec, repr: ReprOptions) -> Self { let mut flags = AdtFlags::NO_ADT_FLAGS; @@ -1410,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } AdtDef { did: did, + discr_ty: discr_ty, variants: variants, flags: Cell::new(flags), destructor: Cell::new(None), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b01b77bbcf8..1df87da4227 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -23,7 +23,7 @@ use ty::TypeVariants::*; use util::nodemap::FxHashMap; use middle::lang_items; -use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; +use rustc_const_math::ConstInt; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; use std::cell::RefCell; @@ -34,14 +34,15 @@ use syntax::ast::{self, Name}; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::Span; +use rustc_i128::i128; + use hir; pub trait IntTypeExt { fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>; fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) -> Option; - fn assert_ty_matches(&self, val: Disr); - fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; + fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; } impl IntTypeExt for attr::IntType { @@ -62,56 +63,18 @@ impl IntTypeExt for attr::IntType { } } - fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { - match *self { - 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 initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { + 0 } + /// None = overflow fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) - -> Option { + -> Option { if let Some(val) = val { - self.assert_ty_matches(val); - (val + ConstInt::Infer(1)).ok() + match *self { + SignedInt(it) => ConstInt::new_signed(val as i128, it, tcx.sess.target.int_type), + UnsignedInt(it) => ConstInt::new_unsigned(val, it, tcx.sess.target.uint_type), + }.and_then(|l| (l + ConstInt::Infer(1)).ok()).map(|v| v.to_u128_unchecked()) } else { Some(self.initial_discriminant(tcx)) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index bb99be20f64..88c04d88a6f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -25,8 +25,6 @@ use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; -use rustc_const_math::ConstInt; - use rustc::mir::Mir; use std::borrow::Cow; @@ -435,7 +433,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Mod(_) => Def::Mod(did), EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), - EntryKind::Enum(_) => Def::Enum(did), + EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did), EntryKind::ForeignMod | @@ -535,7 +533,7 @@ impl<'a, 'tcx> CrateMetadata { vis: f.visibility.decode(self) } }).collect(), - disr_val: ConstInt::Infer(data.disr), + disr_val: data.disr, ctor_kind: data.ctor_kind, }, data.struct_ctor) } @@ -546,6 +544,12 @@ impl<'a, 'tcx> CrateMetadata { -> &'tcx ty::AdtDef { let item = self.entry(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 variants = if let EntryKind::Enum(_) = item.kind { item.children @@ -562,13 +566,13 @@ impl<'a, 'tcx> CrateMetadata { vec![variant] }; 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::Union(_, repr) => (ty::AdtKind::Union, repr), _ => 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 { // Make adt definition available through constructor id as well. tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f4ff5f4626f..b913f68e584 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u128_unchecked(), + disr: variant.disr_val, struct_ctor: None, }; @@ -388,7 +388,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u128_unchecked(), + disr: variant.disr_val, struct_ctor: Some(def_id.index), }; @@ -661,7 +661,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemForeignMod(_) => EntryKind::ForeignMod, 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, _) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); @@ -678,7 +678,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u128_unchecked(), + disr: variant.disr_val, struct_ctor: struct_ctor, }), repr_options) } @@ -688,7 +688,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u128_unchecked(), + disr: variant.disr_val, struct_ctor: None, }), repr_options) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 10aa4784aa2..777af02772e 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -228,7 +228,7 @@ pub enum EntryKind<'tcx> { ForeignMutStatic, ForeignMod, Type, - Enum(ReprOptions), + Enum(Lazy, ReprOptions), Field, Variant(Lazy), Struct(Lazy, ReprOptions), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 7578cc74dbf..9ae83991962 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1473,7 +1473,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), name.as_ptr(), // FIXME: what if enumeration has i128 discriminant? - v.disr_val.to_u128_unchecked() as u64) + v.disr_val as u64) } }) .collect(); diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs index c5737c6e5f1..f3a62bc85b8 100644 --- a/src/librustc_trans/disr.rs +++ b/src/librustc_trans/disr.rs @@ -27,7 +27,7 @@ impl ::std::ops::BitAnd for Disr { impl From<::rustc::ty::Disr> for Disr { fn from(i: ::rustc::ty::Disr) -> Disr { // FIXME: what if discr has 128 bit discr? - Disr(i.to_u128_unchecked() as u64) + Disr(i as u64) } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7936db65c44..c1b4531f85e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1004,9 +1004,8 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = ccx.tcx.hir.local_def_id(it.id); // 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 variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, - ConstInt::Infer(0), def)]; - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants, + let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)]; + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants, ReprOptions::new(&ccx.tcx, did)); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. @@ -1023,63 +1022,69 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> &'tcx ty::AdtDef { let did = ccx.tcx.hir.local_def_id(it.id); +<<<<<<< HEAD let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did)); +======= + let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)]; + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants); +>>>>>>> b1934037e6... Move type of discriminant to AdtDef ccx.tcx.adt_defs.borrow_mut().insert(did, adt); adt } - fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId) - -> Option { - let e = &ccx.tcx.hir.body(body).value; - debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id)); +fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId) + -> Option { + let e = &ccx.tcx.hir.body(body).value; + debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id)); - let ty_hint = repr_ty.to_ty(ccx.tcx); - let print_err = |cv: ConstVal| { - struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types") - .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) - .span_label(e.span, &format!("expected '{}' type", ty_hint)) - .emit(); - }; + let ty_hint = repr_ty.to_ty(ccx.tcx); + let print_err = |cv: ConstVal| { + struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types") + .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) + .span_label(e.span, &format!("expected '{}' type", ty_hint)) + .emit(); + }; - let hint = UncheckedExprHint(ty_hint); - match ConstContext::new(ccx.tcx, body).eval(e, hint) { - Ok(ConstVal::Integral(i)) => { - // FIXME: eval should return an error if the hint is wrong - match (repr_ty, i) { - (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) | - (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | - (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | - (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | - (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) | - (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | - (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | - (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | - (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | - (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | - (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | - (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i), - (_, i) => { - print_err(ConstVal::Integral(i)); - None - }, - } - }, - Ok(cv) => { - print_err(cv); - None - }, - // enum variant evaluation happens before the global constant check - // so we need to report the real error - Err(err) => { - let mut diag = report_const_eval_err( - ccx.tcx, &err, e.span, "enum discriminant"); - diag.emit(); - None + let hint = UncheckedExprHint(ty_hint); + match ConstContext::new(ccx.tcx, body).eval(e, hint) { + Ok(ConstVal::Integral(i)) => { + // FIXME: eval should return an error if the hint is wrong + match (repr_ty, i) { + (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) | + (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | + (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | + (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | + (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) | + (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | + (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | + (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | + (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | + (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | + (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | + (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => + Some(i.to_u128_unchecked()), + (_, i) => { + print_err(ConstVal::Integral(i)); + None + }, } + }, + Ok(cv) => { + print_err(cv); + None + }, + // enum variant evaluation happens before the global constant check + // so we need to report the real error + Err(err) => { + let mut diag = report_const_eval_err( + ccx.tcx, &err, e.span, "enum discriminant"); + diag.emit(); + None } } +} fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item, @@ -1093,7 +1098,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let initial = repr_type.initial_discriminant(tcx); let mut prev_disr = None::; 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.wrapping_add(1)); let disr = if let Some(e) = v.node.disr_expr { evaluate_disr_expr(ccx, repr_type, e) } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) { @@ -1113,7 +1118,11 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); +<<<<<<< HEAD let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did)); +======= + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants); +>>>>>>> b1934037e6... Move type of discriminant to AdtDef tcx.adt_defs.borrow_mut().insert(did, adt); adt } From 5d70a7fbe489b96272a25b3a75b5f2ef46a846a3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 1 Feb 2017 05:10:35 +0200 Subject: [PATCH 04/21] AdtDef now contains discr_ty same as layouted --- src/Cargo.lock | 1 + src/librustc/ty/layout.rs | 66 +++++++++++++++++++++++++++++----- src/librustc_typeck/Cargo.toml | 1 + src/librustc_typeck/collect.rs | 25 ++++++------- src/librustc_typeck/lib.rs | 2 ++ 5 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 09aefd45e94..8b76381a586 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -578,6 +578,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_platform_intrinsics 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 4d3a17e51c1..b61849abe68 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -382,6 +382,23 @@ impl Integer { } } + pub fn to_attr(&self, signed: bool) -> attr::IntType { + match (*self, signed) { + (I1, false) => attr::IntType::UnsignedInt(UintTy::U8), + (I8, false) => attr::IntType::UnsignedInt(UintTy::U8), + (I16, false) => attr::IntType::UnsignedInt(UintTy::U16), + (I32, false) => attr::IntType::UnsignedInt(UintTy::U32), + (I64, false) => attr::IntType::UnsignedInt(UintTy::U64), + (I128, false) => attr::IntType::UnsignedInt(UintTy::U128), + (I1, true) => attr::IntType::SignedInt(IntTy::I8), + (I8, true) => attr::IntType::SignedInt(IntTy::I8), + (I16, true) => attr::IntType::SignedInt(IntTy::I16), + (I32, true) => attr::IntType::SignedInt(IntTy::I32), + (I64, true) => attr::IntType::SignedInt(IntTy::I64), + (I128, true) => attr::IntType::SignedInt(IntTy::I128), + } + } + /// Find the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i64) -> Integer { match x { @@ -436,18 +453,24 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. +<<<<<<< HEAD fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) -> (Integer, bool) { +======= + pub fn repr_discr(tcx: TyCtxt, hints: &[attr::ReprAttr], min: i128, max: i128) + -> (Integer, bool) { +>>>>>>> cade130ae8... AdtDef now contains discr_ty same as layouted // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there // are any negative values, the only valid unsigned representation is u64 // which can fit all i64 values, so the result remains unaffected. - let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64)); + let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); let mut min_from_extern = None; let min_default = I8; +<<<<<<< HEAD if let Some(ity) = repr.int { let discr = Integer::from_attr(&tcx.data_layout, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; @@ -466,11 +489,40 @@ impl Integer { // lower bound. However, we don't run on those yet...? "arm" => min_from_extern = Some(I32), _ => min_from_extern = Some(I32), +======= + for &r in hints.iter() { + match r { + attr::ReprInt(ity) => { + let discr = Integer::from_attr(&tcx.data_layout, ity); + let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; + if discr < fit { + bug!("Integer::repr_discr: `#[repr]` hint too small for \ + discriminant range of enum") + } + return (discr, ity.is_signed()); + } + attr::ReprExtern => { + match &tcx.sess.target.target.arch[..] { + // WARNING: the ARM EABI has two variants; the one corresponding + // to `at_least == I32` appears to be used on Linux and NetBSD, + // but some systems may use the variant corresponding to no + // lower bound. However, we don't run on those yet...? + "arm" => min_from_extern = Some(I32), + _ => min_from_extern = Some(I32), + } + } + attr::ReprAny => {}, + attr::ReprPacked => { + bug!("Integer::repr_discr: found #[repr(packed)] on enum"); + } + attr::ReprSimd => { + bug!("Integer::repr_discr: found #[repr(simd)] on enum"); + } +>>>>>>> cade130ae8... AdtDef now contains discr_ty same as layouted } } let at_least = min_from_extern.unwrap_or(min_default); - // If there are no negative values, we can use the unsigned fit. if min >= 0 { (cmp::max(unsigned_fit, at_least), false) @@ -1196,9 +1248,8 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME: should handle i128? signed-value based impl is weird and hard to // grok. - let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, - min, - max); + let discr = Integer::from_attr(&tcx.data_layout, def.discr_ty); + let signed = def.discr_ty.is_signed(); return success(CEnum { discr: discr, signed: signed, @@ -1313,10 +1364,7 @@ impl<'a, 'gcx, 'tcx> Layout { } // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max); - + let min_ity = Integer::from_attr(&tcx.data_layout, def.discr_ty); let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e5..06789355242 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -22,3 +22,4 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c1b4531f85e..30bd22454e7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{ConstContext, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions}; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, layout}; use rustc::ty::util::IntTypeExt; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; @@ -86,6 +86,8 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; +use rustc_i128::i128; + /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -1022,14 +1024,9 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> &'tcx ty::AdtDef { let did = ccx.tcx.hir.local_def_id(it.id); -<<<<<<< HEAD - let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did)); -======= let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)]; - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants); ->>>>>>> b1934037e6... Move type of discriminant to AdtDef + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants, + ReprOptions::new(&ccx.tcx, did)); ccx.tcx.adt_defs.borrow_mut().insert(did, adt); adt } @@ -1097,9 +1094,11 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let repr_type = tcx.enum_repr_type(repr_hints.get(0)); let initial = repr_type.initial_discriminant(tcx); let mut prev_disr = None::; + let (mut min, mut max) = (i128::max_value(), i128::min_value()); let variants = def.variants.iter().map(|v| { let wrapped_disr = prev_disr.map_or(initial, |d| d.wrapping_add(1)); let disr = if let Some(e) = v.node.disr_expr { + // FIXME: i128 discriminants evaluate_disr_expr(ccx, repr_type, e) } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) { Some(disr) @@ -1113,16 +1112,14 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, None }.unwrap_or(wrapped_disr); prev_disr = Some(disr); - + if (disr as i128) < min { min = disr as i128; } + if (disr as i128) > max { max = disr as i128; } let did = tcx.hir.local_def_id(v.node.data.id()); convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); -<<<<<<< HEAD - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did)); -======= - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants); ->>>>>>> b1934037e6... Move type of discriminant to AdtDef + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_int.to_attr(signed)), variants, + ReprOptions::new(&ccx.tcx, did)); tcx.adt_defs.borrow_mut().insert(did, adt); adt } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index f19a59a5d38..aa2695b9553 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -98,6 +98,8 @@ extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors as errors; +extern crate rustc_i128; + pub use rustc::dep_graph; pub use rustc::hir; pub use rustc::lint; From aac82d9b13f8ba1baebc5a2a1a673831e6f6fbe7 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 02:05:56 +0200 Subject: [PATCH 05/21] SwitchInt over Switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes another special case of Switch by replacing it with the more general SwitchInt. While this is more clunky currently, there’s no reason we can’t make it nice (and efficient) to use. --- src/librustc/middle/const_val.rs | 1 + src/librustc/mir/mod.rs | 17 +----- src/librustc/mir/tcx.rs | 12 +++-- src/librustc/mir/visit.rs | 9 ---- src/librustc/ty/util.rs | 20 ++----- .../borrowck/mir/dataflow/mod.rs | 1 - .../borrowck/mir/elaborate_drops.rs | 49 +++++++++++------ .../borrowck/mir/gather_moves.rs | 3 +- src/librustc_const_math/int.rs | 8 +++ src/librustc_data_structures/bitvec.rs | 4 ++ src/librustc_mir/build/matches/test.rs | 52 ++++++++++++++----- src/librustc_mir/lib.rs | 2 + src/librustc_mir/transform/no_landing_pads.rs | 1 - src/librustc_mir/transform/qualify_consts.rs | 1 - src/librustc_mir/transform/simplify.rs | 1 - src/librustc_mir/transform/type_check.rs | 14 ----- src/librustc_passes/mir_stats.rs | 1 - src/librustc_trans/mir/analyze.rs | 1 - src/librustc_trans/mir/block.rs | 38 -------------- 19 files changed, 105 insertions(+), 130 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index f583f601726..c4e3827fef2 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,6 +14,7 @@ use std::rc::Rc; use hir::def_id::DefId; use rustc_const_math::*; use self::ConstVal::*; +pub use rustc_const_math::ConstInt; use std::collections::BTreeMap; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index fa7ba3e6a62..b0a6784c3c3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -453,13 +453,6 @@ pub enum TerminatorKind<'tcx> { target: BasicBlock, }, - /// lvalue evaluates to some enum; jump depending on the branch - Switch { - discr: Lvalue<'tcx>, - adt_def: &'tcx AdtDef, - targets: Vec, - }, - /// operand evaluates to an integer; jump depending on its value /// to one of the targets, and otherwise fallback to `otherwise` SwitchInt { @@ -471,6 +464,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. + // FIXME: ConstVal doesn’t quite make any sense here? Its a Switch*Int*. values: Vec, /// Possible branch sites. The length of this vector should be @@ -544,7 +538,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { Goto { target: ref b } => slice::ref_slice(b).into_cow(), - Switch { targets: ref b, .. } => b[..].into_cow(), SwitchInt { targets: ref b, .. } => b[..].into_cow(), Resume => (&[]).into_cow(), Return => (&[]).into_cow(), @@ -573,7 +566,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { Goto { target: ref mut b } => vec![b], - Switch { targets: ref mut b, .. } => b.iter_mut().collect(), SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), Resume => Vec::new(), Return => Vec::new(), @@ -651,7 +643,6 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { Goto { .. } => write!(fmt, "goto"), - Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv), SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), Return => write!(fmt, "return"), Resume => write!(fmt, "resume"), @@ -701,12 +692,6 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Unreachable => vec![], Goto { .. } => vec!["".into()], - Switch { ref adt_def, .. } => { - adt_def.variants - .iter() - .map(|variant| variant.name.to_string().into()) - .collect() - } SwitchInt { ref values, .. } => { values.iter() .map(|const_val| { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 68fbadd5d60..fcfd1c57672 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -17,6 +17,7 @@ use mir::*; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use syntax::attr; use hir; #[derive(Copy, Clone, Debug)] @@ -170,9 +171,14 @@ impl<'tcx> Rvalue<'tcx> { Some(operand.ty(mir, tcx)) } Rvalue::Discriminant(ref lval) => { - if let ty::TyAdt(_, _) = lval.ty(mir, tcx).to_ty(tcx).sty { - // TODO - None + if let ty::TyAdt(adt_def, _) = lval.ty(mir, tcx).to_ty(tcx).sty { + // FIXME: Why this does not work? + // Some(adt_def.discr_ty.to_ty(tcx)) + let ty = match adt_def.discr_ty { + attr::SignedInt(i) => tcx.mk_mach_int(i), + attr::UnsignedInt(i) => tcx.mk_mach_uint(i), + }; + Some(ty) } else { None } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 1e27a02287f..ca20cf6236b 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -362,15 +362,6 @@ macro_rules! make_mir_visitor { 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, ref $($mutability)* switch_ty, ref $($mutability)* values, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1df87da4227..fe4b6dad30e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -39,27 +39,17 @@ use rustc_i128::i128; use hir; pub trait IntTypeExt { - fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>; + fn to_ty<'a, 'tcx>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>; fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) -> Option; fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; } impl IntTypeExt for attr::IntType { - fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(ast::IntTy::I8) => tcx.types.i8, - SignedInt(ast::IntTy::I16) => tcx.types.i16, - 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 to_ty<'a, 'gcx, 'tcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + match self { + SignedInt(i) => tcx.mk_mach_int(i), + UnsignedInt(i) => tcx.mk_mach_uint(i), } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 8dd591fa2e7..8b246105f61 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -454,7 +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, unwind); } - mir::TerminatorKind::Switch { ref targets, .. } | mir::TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { self.propagate_bits_into_entry_set_for(in_out, changed, target); diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 45f534767e4..8f3dcd0b8d6 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -17,9 +17,10 @@ use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::util::IntTypeExt; use rustc::mir::*; 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::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; @@ -672,12 +673,15 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.drop_ladder(c, fields) } _ => { - let variant_drops : Vec = - (0..adt.variants.len()).map(|i| { - self.open_drop_for_variant(c, &mut drop_block, - adt, substs, i) - }).collect(); - + let mut values = Vec::with_capacity(adt.variants.len()); + let mut blocks = Vec::with_capacity(adt.variants.len() + 1); + for (idx, variant) in adt.variants.iter().enumerate() { + let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty, + self.tcx.sess.target.uint_type, + self.tcx.sess.target.int_type).unwrap(); + values.push(ConstVal::Integral(discr)); + blocks.push(self.open_drop_for_variant(c, &mut drop_block, adt, substs, idx)); + } // If there are multiple variants, then if something // is present within the enum the discriminant, tracked // by the rest path, must be initialized. @@ -685,14 +689,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // Additionally, we do not want to switch on the // discriminant after it is free-ed, because that // way lies only trouble. - - let switch_block = self.new_block( - c, c.is_cleanup, TerminatorKind::Switch { - discr: c.lvalue.clone(), - adt_def: adt, - targets: variant_drops - }); - + let discr_ty = adt.discr_ty.to_ty(self.tcx); + let discr = Lvalue::Local(self.patch.new_temp(discr_ty)); + let switch_block = self.patch.new_block(BasicBlockData { + statements: vec![ + Statement { + 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: values, + targets: blocks, + // adt_def: adt, + // targets: variant_drops + } + }), + is_cleanup: c.is_cleanup, + }); self.drop_flag_test_block(c, switch_block) } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 9e7e5ec9ee8..0c7e922c48a 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -465,8 +465,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } TerminatorKind::Assert { .. } | - TerminatorKind::SwitchInt { .. } | - TerminatorKind::Switch { .. } => { + TerminatorKind::SwitchInt { .. } => { // branching terminators - these don't move anything } diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 17714f2fb2d..bc3809db1c6 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -77,6 +77,14 @@ mod ibounds { } impl ConstInt { + pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy) + -> Option { + 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 /// not happen. pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option { diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 3700d46c346..ffcd25a4cdd 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -30,6 +30,10 @@ impl BitVector { } } + pub fn count(&self) -> usize { + self.data.iter().map(|e| e.count_ones() as usize).sum() + } + #[inline] pub fn contains(&self, bit: usize) -> bool { let (word, mask) = word_mask(bit); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 291bd65d577..528e37e73c4 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -20,11 +20,12 @@ use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; use rustc_data_structures::fx::FxHashMap; 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::mir::*; use rustc::hir::RangeEnd; use syntax_pos::Span; +use syntax::attr; use std::cmp::Ordering; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -182,24 +183,51 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(test.span); match test.kind { 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 used_variants = variants.count(); let mut otherwise_block = None; - let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| { - if variants.contains(i) { - self.cfg.start_new_block() + let mut target_blocks = Vec::with_capacity(num_enum_variants); + let mut targets = Vec::with_capacity(used_variants + 1); + 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(ConstVal::Integral(discr)); + *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { otherwise_block = Some(self.cfg.start_new_block()); } otherwise_block.unwrap() - } - }).collect(); - debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}", - num_enum_variants, variants.iter().count(), variants); - self.cfg.terminate(block, source_info, TerminatorKind::Switch { - discr: lvalue.clone(), - adt_def: adt_def, - targets: target_blocks.clone() + }; + } + if let Some(otherwise_block) = otherwise_block { + targets.push(otherwise_block); + } else { + values.pop(); + } + debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", + num_enum_variants, values, variants); + // FIXME: WHY THIS DOES NOT WORK?! + // let discr_ty = adt_def.discr_ty.to_ty(tcx); + let discr_ty = match adt_def.discr_ty { + attr::SignedInt(i) => tcx.mk_mach_int(i), + attr::UnsignedInt(i) => tcx.mk_mach_uint(i), + }; + + 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: values, + targets: targets }); target_blocks } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 61ba9d90fef..9a8fb1099d0 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -26,6 +26,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] +#![feature(placement_in_syntax)] +#![feature(collection_placement)] #[macro_use] extern crate log; extern crate graphviz as dot; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 425df65659c..55a26f4b37f 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -28,7 +28,6 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::Unreachable | - TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => { /* nothing to do */ }, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index bda4c94625f..922521726c6 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -394,7 +394,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return Qualif::empty(); } - TerminatorKind::Switch {..} | TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 1127f50fe50..e93a412dc74 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -209,7 +209,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { // turn a branch with all successors identical to a goto fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { match terminator.kind { - TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => {}, _ => return false }; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 9d2ad314386..8ede7aaab5f 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -436,19 +436,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } // 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, .. } => { let func_ty = func.ty(mir, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); @@ -593,7 +580,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match block.terminator().kind { TerminatorKind::Goto { target } => self.assert_iscleanup(mir, block, target, is_cleanup), - TerminatorKind::Switch { ref targets, .. } | TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { self.assert_iscleanup(mir, block, *target, is_cleanup); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index fef61128d04..517a4720563 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -148,7 +148,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record("TerminatorKind", kind); self.record(match *kind { TerminatorKind::Goto { .. } => "TerminatorKind::Goto", - TerminatorKind::Switch { .. } => "TerminatorKind::Switch", TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", TerminatorKind::Resume => "TerminatorKind::Resume", TerminatorKind::Return => "TerminatorKind::Return", diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 97118a72062..37725bfa2de 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -204,7 +204,6 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { /* nothing to do */ } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b22c16a2955..2ed2cc61062 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -14,14 +14,12 @@ use rustc::middle::lang_items; use rustc::ty::{self, layout, TypeFoldable}; use rustc::mir; use abi::{Abi, FnType, ArgType}; -use adt; use base::{self, Lifetime}; use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual}; use builder::Builder; use common::{self, Funclet}; use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef}; use consts; -use Disr; use machine::{llalign_of_min, llbitsize_of_real}; use meth; use type_of::{self, align_of}; @@ -29,7 +27,6 @@ use glue; use type_::Type; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::fx::FxHashMap; use syntax::symbol::Symbol; use std::cmp; @@ -136,41 +133,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { funclet_br(self, bcx, target); } - 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 } => { // TODO: cond_br if only 1 value let (otherwise, targets) = targets.split_last().unwrap(); From a00a0adc7913152bff626d6dbebfa2cfdbb93d0a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 06:44:30 +0200 Subject: [PATCH 06/21] Only SwitchInt over integers, not all consts Also use a Cow to avoid full Vec for all SwitchInts --- src/librustc/middle/const_val.rs | 13 +++ src/librustc/mir/mod.rs | 8 +- src/librustc/mir/visit.rs | 19 +++- .../borrowck/mir/elaborate_drops.rs | 6 +- src/librustc_mir/build/expr/into.rs | 9 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 95 ++++++++----------- src/librustc_trans/mir/block.rs | 27 ++++-- src/librustc_trans/mir/constant.rs | 48 ++++++---- src/libserialize/serialize.rs | 28 ++++++ 10 files changed, 154 insertions(+), 101 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index c4e3827fef2..f885a6d9569 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,6 +11,7 @@ use syntax::symbol::InternedString; use syntax::ast; use std::rc::Rc; +use std::borrow::Cow; use hir::def_id::DefId; use rustc_const_math::*; use self::ConstVal::*; @@ -18,6 +19,8 @@ pub use rustc_const_math::ConstInt; use std::collections::BTreeMap; +pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]); + #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal { Float(ConstFloat), @@ -49,4 +52,14 @@ impl ConstVal { Char(..) => "char", } } + + pub fn to_const_int(&self) -> Option { + 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 + } + } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index b0a6784c3c3..28990fd323f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -446,6 +446,9 @@ pub struct Terminator<'tcx> { pub kind: TerminatorKind<'tcx> } +/// For use in SwitchInt, for switching on bools. +pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]); + #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum TerminatorKind<'tcx> { /// block should have one successor in the graph; we jump there @@ -464,8 +467,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - // FIXME: ConstVal doesn’t quite make any sense here? Its a Switch*Int*. - values: Vec, + values: Cow<'tcx, [ConstInt]>, /// Possible branch sites. The length of this vector should be /// equal to the length of the `values` vector plus 1 -- the @@ -696,7 +698,7 @@ impl<'tcx> TerminatorKind<'tcx> { values.iter() .map(|const_val| { 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() }) .chain(iter::once(String::from("otherwise").into())) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ca20cf6236b..be3c43db7ba 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -223,6 +223,12 @@ macro_rules! make_mir_visitor { 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, const_usize: & $($mutability)* ConstUsize, _: Location) { @@ -364,12 +370,12 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { ref $($mutability)* discr, ref $($mutability)* switch_ty, - ref $($mutability)* values, + ref values, ref targets } => { self.visit_operand(discr, source_location); self.visit_ty(switch_ty); - for value in values { - self.visit_const_val(value, source_location); + for value in &values[..] { + self.visit_const_int(value, source_location); } for &target in targets { self.visit_branch(block, target); @@ -698,10 +704,13 @@ macro_rules! make_mir_visitor { _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 diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 8f3dcd0b8d6..53e84f1fb71 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -679,7 +679,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty, self.tcx.sess.target.uint_type, self.tcx.sess.target.int_type).unwrap(); - values.push(ConstVal::Integral(discr)); + values.push(discr); blocks.push(self.open_drop_for_variant(c, &mut drop_block, adt, substs, idx)); } // If there are multiple variants, then if something @@ -704,7 +704,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { kind: TerminatorKind::SwitchInt { discr: Operand::Consume(discr), switch_ty: discr_ty, - values: values, + values: From::from(values), targets: blocks, // adt_def: adt, // targets: variant_drops @@ -836,7 +836,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.new_block(c, is_cleanup, TerminatorKind::SwitchInt { discr: Operand::Consume(flag), switch_ty: boolty, - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![on_set, on_unset], }) } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 2b4336ba66f..537daa4a15b 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -15,7 +15,6 @@ use build::expr::category::{Category, RvalueFunc}; use hair::*; use rustc::ty; use rustc::mir::*; -use rustc::middle::const_val::ConstVal; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which @@ -73,7 +72,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: operand, switch_ty: this.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![then_block, else_block], }); @@ -120,7 +119,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: lhs, switch_ty: this.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: blocks, }); @@ -128,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt { discr: rhs, switch_ty: this.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![true_block, false_block], }); @@ -192,7 +191,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::SwitchInt { discr: cond, switch_ty: this.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![body_block, exit_block], }); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 0898d06d2e4..885965da1f9 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -675,7 +675,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: cond, switch_ty: self.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![arm_block, otherwise], }); Some(otherwise) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 528e37e73c4..f2d48f65fef 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -196,7 +196,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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(ConstVal::Integral(discr)); + values.push(discr); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { @@ -226,59 +226,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(discr), switch_ty: discr_ty, - values: values, + values: From::from(values), targets: targets }); target_blocks } TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { - let (targets, term) = match switch_ty.sty { - // If we're matching on boolean we can - // use the If TerminatorKind instead - ty::TyBool => { - assert!(options.len() > 0 && options.len() <= 2); - - let (true_bb, else_bb) = - (self.cfg.start_new_block(), - self.cfg.start_new_block()); - - let targets = match &options[0] { - &ConstVal::Bool(true) => vec![true_bb, else_bb], - &ConstVal::Bool(false) => vec![else_bb, true_bb], - v => span_bug!(test.span, "expected boolean value but got {:?}", v) - }; - - (targets, TerminatorKind::SwitchInt { - discr: Operand::Consume(lvalue.clone()), - switch_ty: self.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], - targets: vec![true_bb, else_bb] - }) - - } - _ => { - // The switch may be inexhaustive so we - // add a catch all block - let otherwise = self.cfg.start_new_block(); - let targets: Vec<_> = - options.iter() - .map(|_| self.cfg.start_new_block()) - .chain(Some(otherwise)) - .collect(); - - (targets.clone(), - TerminatorKind::SwitchInt { - discr: Operand::Consume(lvalue.clone()), - switch_ty: switch_ty, - values: options.clone(), - targets: targets - }) - } + let (values, targets, ret) = if switch_ty.sty == ty::TyBool { + assert!(options.len() > 0 && options.len() <= 2); + let (true_bb, false_bb) = (self.cfg.start_new_block(), + self.cfg.start_new_block()); + let ret = match &options[0] { + &ConstVal::Bool(true) => vec![true_bb, false_bb], + &ConstVal::Bool(false) => vec![false_bb, true_bb], + v => span_bug!(test.span, "expected boolean value but got {:?}", v) + }; + (BOOL_SWITCH_TRUE.clone(), vec![true_bb, false_bb], ret) + } else { + // The switch may be inexhaustive so we + // add a catch all block + let otherwise = self.cfg.start_new_block(); + let targets: Vec<_> = + options.iter() + .map(|_| self.cfg.start_new_block()) + .chain(Some(otherwise)) + .collect(); + let values: Vec<_> = options.iter().map(|v| + v.to_const_int().expect("switching on integral") + ).collect(); + (From::from(values), targets.clone(), targets) }; - self.cfg.terminate(block, source_info, term); - targets + self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: Operand::Consume(lvalue.clone()), + switch_ty: switch_ty, + values: values, + targets: targets.clone(), + }); + ret } TestKind::Eq { ref value, mut ty } => { @@ -346,10 +332,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(eq_result), switch_ty: self.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![block, fail], }); - vec![block, fail] } else { let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); @@ -391,16 +376,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Operand::Consume(expected))); // branch based on result - let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), - self.cfg.start_new_block()]; + let (false_bb, true_bb) = (self.cfg.start_new_block(), + self.cfg.start_new_block()); self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(result), switch_ty: self.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], - targets: target_blocks.clone(), + values: BOOL_SWITCH_TRUE.clone(), + targets: vec![true_bb, false_bb], }); - - target_blocks + vec![true_bb, false_bb] } } } @@ -425,10 +409,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(result), switch_ty: self.hir.bool_ty(), - values: vec![ConstVal::Bool(true)], + values: BOOL_SWITCH_TRUE.clone(), targets: vec![target_block, fail_block] }); - target_block } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 2ed2cc61062..651d0066b12 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -11,6 +11,7 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; +use rustc::middle::const_val::ConstInt; use rustc::ty::{self, layout, TypeFoldable}; use rustc::mir; use abi::{Abi, FnType, ArgType}; @@ -134,14 +135,24 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - // TODO: cond_br if only 1 value - let (otherwise, targets) = targets.split_last().unwrap(); - let discr = self.trans_operand(&bcx, discr).immediate(); - let switch = bcx.switch(discr, llblock(self, *otherwise), values.len()); - for (value, target) in values.iter().zip(targets) { - let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty); - let llbb = llblock(self, *target); - bcx.add_case(switch, val.llval, llbb) + 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 switch = bcx.switch(discr.immediate(), + llblock(self, *otherwise), values.len()); + for (value, target) in values.iter().zip(targets) { + let val = Const::from_constint(bcx.ccx, value); + let llbb = llblock(self, *target); + bcx.add_case(switch, val.llval, llbb) + } } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 11668e792e3..19139301bb0 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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. pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, cv: ConstVal, @@ -72,26 +99,7 @@ impl<'tcx> Const<'tcx> { ConstVal::Float(F64(v)) => C_floating_f64(v, llty), ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv), ConstVal::Bool(v) => C_bool(ccx, v), - ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true), - 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::Integral(ref i) => return Const::from_constint(ccx, i), 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::Struct(_) | ConstVal::Tuple(_) | diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index ba39fcdec6f..c6847249803 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -567,6 +567,34 @@ impl Decodable for Vec { } } +impl<'a, T:Encodable> Encodable for Cow<'a, [T]> +where [T]: ToOwned> +{ + fn encode(&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 Decodable for Cow<'static, [T]> +where [T]: ToOwned> +{ + fn decode(d: &mut D) -> Result, 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 Encodable for Option { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_option(|s| { From 92c56f607b24e5ef5dcbc70ac442c88c296e4591 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 07:25:29 +0200 Subject: [PATCH 07/21] Fix build on further stages --- src/librustc/ty/layout.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b61849abe68..3a7acc5c7b5 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -400,7 +400,7 @@ impl Integer { } /// Find the smallest Integer type which can represent the signed value. - pub fn fit_signed(x: i64) -> Integer { + pub fn fit_signed(x: i128) -> Integer { match x { -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1, -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, @@ -412,7 +412,7 @@ impl Integer { } /// Find the smallest Integer type which can represent the unsigned value. - pub fn fit_unsigned(x: u64) -> Integer { + pub fn fit_unsigned(x: u128) -> Integer { match x { 0...0x0000_0000_0000_0001 => I1, 0...0x0000_0000_0000_00ff => I8, From 64182a587c0c26559b166cbf45ab33f10b332ffc Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 08:41:01 +0200 Subject: [PATCH 08/21] Reimplement simplify_cfg for SwitchInt First example of optimisation that applies to many more cases than originally. --- .../transform/simplify_branches.rs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 424250586b1..3d5106c4b06 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -30,26 +30,30 @@ impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> { for block in mir.basic_blocks_mut() { let terminator = block.terminator_mut(); terminator.kind = match terminator.kind { - // TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { - // literal: Literal::Value { - // value: ConstVal::Bool(cond) - // }, .. - // }) } => { - // if cond { - // TerminatorKind::Goto { target: targets.0 } - // } else { - // TerminatorKind::Goto { target: targets.1 } - // } - // } - + TerminatorKind::SwitchInt { discr: Operand::Constant(Constant { + literal: Literal::Value { ref value }, .. + }), ref values, ref targets, .. } => { + if let Some(ref constint) = value.to_const_int() { + let (otherwise, targets) = targets.split_last().unwrap(); + let mut ret = TerminatorKind::Goto { target: *otherwise }; + for (v, t) in values.iter().zip(targets.iter()) { + if v == constint { + ret = TerminatorKind::Goto { target: *t }; + break; + } + } + ret + } else { + continue + } + }, TerminatorKind::Assert { target, cond: Operand::Constant(Constant { literal: Literal::Value { value: ConstVal::Bool(cond) }, .. }), expected, .. } if cond == expected => { TerminatorKind::Goto { target: target } - } - + }, _ => continue }; } From c9939863ca5983614e8e70e0abdb088af60ac590 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 19:53:44 +0200 Subject: [PATCH 09/21] Fix the IntTypeExt::to_ty() lifetime bounds --- src/librustc/mir/tcx.rs | 10 +---- src/librustc/ty/layout.rs | 38 +------------------ src/librustc/ty/util.rs | 4 +- .../borrowck/mir/elaborate_drops.rs | 2 - src/librustc_mir/build/matches/test.rs | 10 +---- src/librustc_trans/mir/rvalue.rs | 1 - src/librustc_typeck/collect.rs | 3 +- 7 files changed, 9 insertions(+), 59 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index fcfd1c57672..6863468ec0d 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -17,8 +17,8 @@ use mir::*; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use syntax::attr; use hir; +use ty::util::IntTypeExt; #[derive(Copy, Clone, Debug)] pub enum LvalueTy<'tcx> { @@ -172,13 +172,7 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::Discriminant(ref lval) => { if let ty::TyAdt(adt_def, _) = lval.ty(mir, tcx).to_ty(tcx).sty { - // FIXME: Why this does not work? - // Some(adt_def.discr_ty.to_ty(tcx)) - let ty = match adt_def.discr_ty { - attr::SignedInt(i) => tcx.mk_mach_int(i), - attr::UnsignedInt(i) => tcx.mk_mach_uint(i), - }; - Some(ty) + Some(adt_def.discr_ty.to_ty(tcx)) } else { None } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3a7acc5c7b5..70ae799d350 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -453,13 +453,8 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. -<<<<<<< HEAD - fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) + fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i128, max: i128) -> (Integer, bool) { -======= - pub fn repr_discr(tcx: TyCtxt, hints: &[attr::ReprAttr], min: i128, max: i128) - -> (Integer, bool) { ->>>>>>> cade130ae8... AdtDef now contains discr_ty same as layouted // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there // are any negative values, the only valid unsigned representation is u64 @@ -470,7 +465,6 @@ impl Integer { let mut min_from_extern = None; let min_default = I8; -<<<<<<< HEAD if let Some(ity) = repr.int { let discr = Integer::from_attr(&tcx.data_layout, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; @@ -489,36 +483,6 @@ impl Integer { // lower bound. However, we don't run on those yet...? "arm" => min_from_extern = Some(I32), _ => min_from_extern = Some(I32), -======= - for &r in hints.iter() { - match r { - attr::ReprInt(ity) => { - let discr = Integer::from_attr(&tcx.data_layout, ity); - let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; - if discr < fit { - bug!("Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum") - } - return (discr, ity.is_signed()); - } - attr::ReprExtern => { - match &tcx.sess.target.target.arch[..] { - // WARNING: the ARM EABI has two variants; the one corresponding - // to `at_least == I32` appears to be used on Linux and NetBSD, - // but some systems may use the variant corresponding to no - // lower bound. However, we don't run on those yet...? - "arm" => min_from_extern = Some(I32), - _ => min_from_extern = Some(I32), - } - } - attr::ReprAny => {}, - attr::ReprPacked => { - bug!("Integer::repr_discr: found #[repr(packed)] on enum"); - } - attr::ReprSimd => { - bug!("Integer::repr_discr: found #[repr(simd)] on enum"); - } ->>>>>>> cade130ae8... AdtDef now contains discr_ty same as layouted } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fe4b6dad30e..0281e53427d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -39,14 +39,14 @@ use rustc_i128::i128; use hir; 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) -> Option; fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; } impl IntTypeExt for attr::IntType { - fn to_ty<'a, 'gcx, 'tcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match self { SignedInt(i) => tcx.mk_mach_int(i), UnsignedInt(i) => tcx.mk_mach_uint(i), diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 53e84f1fb71..7521b750d5a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -706,8 +706,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { switch_ty: discr_ty, values: From::from(values), targets: blocks, - // adt_def: adt, - // targets: variant_drops } }), is_cleanup: c.is_cleanup, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f2d48f65fef..d9c2e6bb090 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -22,10 +22,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::{ConstVal, ConstInt}; use rustc::ty::{self, Ty}; +use rustc::ty::util::IntTypeExt; use rustc::mir::*; use rustc::hir::RangeEnd; use syntax_pos::Span; -use syntax::attr; use std::cmp::Ordering; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -212,13 +212,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); - // FIXME: WHY THIS DOES NOT WORK?! - // let discr_ty = adt_def.discr_ty.to_ty(tcx); - let discr_ty = match adt_def.discr_ty { - attr::SignedInt(i) => tcx.mk_mach_int(i), - attr::UnsignedInt(i) => tcx.mk_mach_uint(i), - }; - + 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())); diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index fe11e0426df..0810bfcadca 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -438,7 +438,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { 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); - // FIXME: inline this let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, None, true); let discr = if common::val_ty(discr) == Type::i1(bcx.ccx) { bcx.zext(discr, discr_type) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30bd22454e7..2f8258ef616 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1047,7 +1047,8 @@ fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId let hint = UncheckedExprHint(ty_hint); match ConstContext::new(ccx.tcx, body).eval(e, hint) { 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) { (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) | (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | From 4be18488a741b2bf9b6f32c0ae5b21f4c3f6c83e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 20:35:54 +0200 Subject: [PATCH 10/21] Fix SwitchInt building in ElaborateDrops pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously it used to build a switch in a way that didn’t preserve the invariat of SwitchInt. Now it builds it in an optimal way too, where otherwise branch becomes all the branches which did not have partial variant drops. --- src/librustc/mir/mod.rs | 15 ++++++++---- src/librustc/mir/tcx.rs | 7 ++++-- .../borrowck/mir/elaborate_drops.rs | 24 ++++++++++++++----- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 28990fd323f..5657ec157e8 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -469,10 +469,17 @@ pub enum TerminatorKind<'tcx> { /// are found in the corresponding indices from the `targets` vector. values: Cow<'tcx, [ConstInt]>, - /// Possible branch sites. The length of this vector should be - /// equal to the length of the `values` vector plus 1 -- the - /// extra item is the block to branch to if none of the values - /// fit. + /// Possible branch sites. The last element of this vector is used + /// for the otherwise branch, so values.len() == targets.len() + 1 + /// should hold. + // 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 // 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, }, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6863468ec0d..7b0863b4c42 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -171,10 +171,13 @@ impl<'tcx> Rvalue<'tcx> { Some(operand.ty(mir, tcx)) } Rvalue::Discriminant(ref lval) => { - if let ty::TyAdt(adt_def, _) = lval.ty(mir, tcx).to_ty(tcx).sty { + 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 { - None + // 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) => { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 7521b750d5a..144b0c2203a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -626,7 +626,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>, variant_index: usize) - -> BasicBlock + -> (BasicBlock, bool) { let subpath = super::move_path_children_matching( self.move_data(), c.path, |proj| match proj { @@ -645,13 +645,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { variant_path, &adt.variants[variant_index], substs); - self.drop_ladder(c, fields) + (self.drop_ladder(c, fields), true) } 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(); + (drop_block.unwrap(), false) } } @@ -674,13 +674,25 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } _ => { let mut values = Vec::with_capacity(adt.variants.len()); - let mut blocks = Vec::with_capacity(adt.variants.len() + 1); + let mut blocks = Vec::with_capacity(adt.variants.len()); + let mut otherwise = None; for (idx, variant) in adt.variants.iter().enumerate() { let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty, self.tcx.sess.target.uint_type, self.tcx.sess.target.int_type).unwrap(); - values.push(discr); - blocks.push(self.open_drop_for_variant(c, &mut drop_block, adt, substs, idx)); + let (blk, is_ladder) = self.open_drop_for_variant(c, &mut drop_block, adt, + substs, idx); + if is_ladder { + values.push(discr); + blocks.push(blk); + } else { + otherwise = Some(blk) + } + } + if let Some(block) = otherwise { + blocks.push(block); + } else { + values.pop(); } // If there are multiple variants, then if something // is present within the enum the discriminant, tracked From 8e00d28ff43e04b7cfcfe7445061b73985f9f1b8 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 22:03:23 +0200 Subject: [PATCH 11/21] Prefer switching on false for boolean switches This ends up not really mattering because we generate a plain conditional branch in LLVM either way. --- src/librustc/middle/const_val.rs | 3 --- src/librustc/mir/mod.rs | 2 +- .../borrowck/mir/elaborate_drops.rs | 4 ++-- src/librustc_mir/build/expr/into.rs | 18 +++++++++--------- src/librustc_mir/build/matches/mod.rs | 4 ++-- src/librustc_mir/build/matches/test.rs | 14 +++++++------- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index f885a6d9569..11919db479c 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,6 @@ use syntax::symbol::InternedString; use syntax::ast; use std::rc::Rc; -use std::borrow::Cow; use hir::def_id::DefId; use rustc_const_math::*; use self::ConstVal::*; @@ -19,8 +18,6 @@ pub use rustc_const_math::ConstInt; use std::collections::BTreeMap; -pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]); - #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal { Float(ConstFloat), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 5657ec157e8..98693d469ed 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -447,7 +447,7 @@ pub struct Terminator<'tcx> { } /// For use in SwitchInt, for switching on bools. -pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]); +pub static BOOL_SWITCH_FALSE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(0)]); #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum TerminatorKind<'tcx> { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 144b0c2203a..44b85c31d86 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -846,8 +846,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.new_block(c, is_cleanup, TerminatorKind::SwitchInt { discr: Operand::Consume(flag), switch_ty: boolty, - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![on_set, on_unset], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![on_unset, on_set], }) } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 537daa4a15b..f61b4a66077 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -72,8 +72,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: operand, switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![then_block, else_block], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![else_block, then_block], }); unpack!(then_block = this.into(destination, then_block, then_expr)); @@ -113,13 +113,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs = unpack!(block = this.as_operand(block, lhs)); let blocks = match op { - LogicalOp::And => vec![else_block, false_block], - LogicalOp::Or => vec![true_block, else_block], + LogicalOp::And => vec![false_block, else_block], + LogicalOp::Or => vec![else_block, true_block], }; this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: lhs, switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), + values: BOOL_SWITCH_FALSE.clone(), targets: blocks, }); @@ -127,8 +127,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt { discr: rhs, switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![true_block, false_block], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![false_block, true_block], }); this.cfg.push_assign_constant( @@ -191,8 +191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::SwitchInt { discr: cond, switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![body_block, exit_block], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![exit_block, body_block], }); // if the test is false, there's no `break` to assign `destination`, so diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 885965da1f9..812900b6bec 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -675,8 +675,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: cond, switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![arm_block, otherwise], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![otherwise, arm_block], }); Some(otherwise) } else { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index d9c2e6bb090..f268eda4c15 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -236,7 +236,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &ConstVal::Bool(false) => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; - (BOOL_SWITCH_TRUE.clone(), vec![true_bb, false_bb], ret) + (BOOL_SWITCH_FALSE.clone(), vec![false_bb, true_bb], ret) } else { // The switch may be inexhaustive so we // add a catch all block @@ -326,8 +326,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(eq_result), switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![block, fail], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![fail, block], }); vec![block, fail] } else { @@ -375,8 +375,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(result), switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![true_bb, false_bb], + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![false_bb, true_bb], }); vec![true_bb, false_bb] } @@ -403,8 +403,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { discr: Operand::Consume(result), switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_TRUE.clone(), - targets: vec![target_block, fail_block] + values: BOOL_SWITCH_FALSE.clone(), + targets: vec![fail_block, target_block] }); target_block } From 76d9a4e646ee7511fd4b2086e67626e9db1bc270 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 22:53:21 +0200 Subject: [PATCH 12/21] Fix codegen test --- src/test/codegen/match.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs index ac47f6082e3..c35206e6e0a 100644 --- a/src/test/codegen/match.rs +++ b/src/test/codegen/match.rs @@ -20,9 +20,13 @@ pub enum E { // CHECK-LABEL: @exhaustive_match #[no_mangle] pub fn exhaustive_match(e: E) { -// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]] -// CHECK: [[DEFAULT]]: -// CHECK-NEXT: unreachable +// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [ +// CHECK-NEXT: i8 [[DISCR:[0-9]+]], label %[[TRUE:[a-zA-Z0-9_]+]] +// 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 { E::A => (), E::B => (), From 362eb7ea0705b02164f93b0a90f292b5eee210c5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 00:07:31 +0200 Subject: [PATCH 13/21] Inspect now does not force on-stack Lvalue --- src/librustc_trans/mir/analyze.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 37725bfa2de..2c3b479c7dd 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -156,10 +156,10 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { LvalueContext::StorageLive | LvalueContext::StorageDead | + LvalueContext::Inspect | LvalueContext::Consume => {} LvalueContext::Store | - LvalueContext::Inspect | LvalueContext::Borrow { .. } | LvalueContext::Projection(..) => { self.mark_as_lvalue(index); From a8b7b6218565f50a682d4367714066c0c4e7517c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 02:34:29 +0200 Subject: [PATCH 14/21] Revert use of layout code in typeck::collect --- src/librustc/ty/layout.rs | 9 +++++---- src/librustc/ty/mod.rs | 7 ++++++- src/librustc/ty/util.rs | 18 ------------------ src/librustc_trans/mir/rvalue.rs | 8 ++------ src/librustc_typeck/collect.rs | 27 ++++++++++++--------------- 5 files changed, 25 insertions(+), 44 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 70ae799d350..46161c8838d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -453,7 +453,7 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i128, max: i128) + pub fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i128, max: i128) -> (Integer, bool) { // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there @@ -1212,8 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME: should handle i128? signed-value based impl is weird and hard to // grok. - let discr = Integer::from_attr(&tcx.data_layout, def.discr_ty); - let signed = def.discr_ty.is_signed(); + let (discr, signed) = Integer::repr_discr(tcx, ty, hints, min, max); return success(CEnum { discr: discr, signed: signed, @@ -1328,7 +1327,9 @@ impl<'a, 'gcx, 'tcx> Layout { } // The general case. - let min_ity = Integer::from_attr(&tcx.data_layout, def.discr_ty); + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max); let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5ec27b57c37..523c61d404f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1326,7 +1326,12 @@ pub struct FieldDef { /// table. pub struct AdtDef { pub did: DefId, - pub discr_ty: attr::IntType, // Type of the discriminant + /// 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, destructor: Cell>, flags: Cell, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 0281e53427d..16492de6c3d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -23,7 +23,6 @@ use ty::TypeVariants::*; use util::nodemap::FxHashMap; use middle::lang_items; -use rustc_const_math::ConstInt; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; use std::cell::RefCell; @@ -34,14 +33,10 @@ use syntax::ast::{self, Name}; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::Span; -use rustc_i128::i128; - use hir; pub trait IntTypeExt { 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) - -> Option; fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; } @@ -56,19 +51,6 @@ impl IntTypeExt for attr::IntType { fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { 0 } - - /// None = overflow - fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) - -> Option { - if let Some(val) = val { - match *self { - SignedInt(it) => ConstInt::new_signed(val as i128, it, tcx.sess.target.int_type), - UnsignedInt(it) => ConstInt::new_unsigned(val, it, tcx.sess.target.uint_type), - }.and_then(|l| (l + ConstInt::Infer(1)).ok()).map(|v| v.to_u128_unchecked()) - } else { - Some(self.initial_discriminant(tcx)) - } - } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 0810bfcadca..2eb4ea6cedd 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -438,12 +438,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { 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, None, true); - let discr = if common::val_ty(discr) == Type::i1(bcx.ccx) { - bcx.zext(discr, discr_type) - } else { - bcx.trunc(discr, discr_type) - }; + let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, + Some(discr_type), true); (bcx, OperandRef { val: OperandValue::Immediate(discr), ty: discr_ty diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2f8258ef616..217405a81ec 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{ConstContext, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions}; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, layout}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; @@ -86,8 +86,6 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc_i128::i128; - /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -1032,7 +1030,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId) - -> Option { + -> Option { let e = &ccx.tcx.hir.body(body).value; debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id)); @@ -1062,7 +1060,7 @@ fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => - Some(i.to_u128_unchecked()), + Some(i), (_, i) => { print_err(ConstVal::Integral(i)); None @@ -1093,15 +1091,17 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = tcx.hir.local_def_id(it.id); let repr_hints = tcx.lookup_repr_hints(did); let repr_type = tcx.enum_repr_type(repr_hints.get(0)); - let initial = repr_type.initial_discriminant(tcx); - let mut prev_disr = None::; - let (mut min, mut max) = (i128::max_value(), i128::min_value()); + let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type, + tcx.sess.target.uint_type, tcx.sess.target.int_type) + .unwrap(); + let mut prev_disr = None::; let variants = def.variants.iter().map(|v| { - let wrapped_disr = prev_disr.map_or(initial, |d| d.wrapping_add(1)); + let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr()); let disr = if let Some(e) = v.node.disr_expr { // FIXME: i128 discriminants 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) } else { struct_span_err!(tcx.sess, v.span, E0370, @@ -1113,13 +1113,10 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, None }.unwrap_or(wrapped_disr); prev_disr = Some(disr); - if (disr as i128) < min { min = disr as i128; } - if (disr as i128) > max { max = disr as i128; } 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(); - - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_int.to_attr(signed)), variants, + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants, ReprOptions::new(&ccx.tcx, did)); tcx.adt_defs.borrow_mut().insert(did, adt); adt From eb727a8faa08557d894506e2f95f2bfdc4996490 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 03:36:32 +0200 Subject: [PATCH 15/21] Add TerminatorKind::if_ convenience constructor Constructs a TerminatorKind::SwitchInt for an equivalent conditional true-false branch. --- src/librustc/mir/mod.rs | 14 +++++-- .../borrowck/mir/elaborate_drops.rs | 9 +---- src/librustc_mir/build/expr/into.rs | 38 ++++++------------- src/librustc_mir/build/matches/mod.rs | 8 +--- src/librustc_mir/build/matches/test.rs | 31 ++++++--------- 5 files changed, 38 insertions(+), 62 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 98693d469ed..d8212807eb2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -446,9 +446,6 @@ pub struct Terminator<'tcx> { pub kind: TerminatorKind<'tcx> } -/// For use in SwitchInt, for switching on bools. -pub static BOOL_SWITCH_FALSE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(0)]); - #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum TerminatorKind<'tcx> { /// block should have one successor in the graph; we jump there @@ -543,6 +540,17 @@ impl<'tcx> Terminator<'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]> { use self::TerminatorKind::*; match *self { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 44b85c31d86..d7ffe538c24 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -842,13 +842,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { (true, false) => on_set, (true, true) => { let flag = self.drop_flag(c.path).unwrap(); - let boolty = self.tcx.types.bool; - self.new_block(c, is_cleanup, TerminatorKind::SwitchInt { - discr: Operand::Consume(flag), - switch_ty: boolty, - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![on_unset, on_set], - }) + let term = TerminatorKind::if_(self.tcx, Operand::Consume(flag), on_set, on_unset); + self.new_block(c, is_cleanup, term) } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index f61b4a66077..35841c2cbdf 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -69,12 +69,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); - this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: operand, - switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![else_block, then_block], - }); + let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block); + this.cfg.terminate(block, source_info, term); unpack!(then_block = this.into(destination, then_block, then_expr)); else_block = if let Some(else_expr) = else_expr { @@ -113,23 +109,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs = unpack!(block = this.as_operand(block, lhs)); let blocks = match op { - LogicalOp::And => vec![false_block, else_block], - LogicalOp::Or => vec![else_block, true_block], + LogicalOp::And => (else_block, false_block), + LogicalOp::Or => (true_block, else_block), }; - this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: lhs, - switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: blocks, - }); + let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); + this.cfg.terminate(block, source_info, term); let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); - this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt { - discr: rhs, - switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![false_block, true_block], - }); + let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); + this.cfg.terminate(else_block, source_info, term); this.cfg.push_assign_constant( true_block, source_info, destination, @@ -187,13 +175,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let cond = unpack!( loop_block_end = this.as_operand(loop_block, cond_expr)); body_block = this.cfg.start_new_block(); - this.cfg.terminate(loop_block_end, source_info, - TerminatorKind::SwitchInt { - discr: cond, - switch_ty: this.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![exit_block, body_block], - }); + let term = TerminatorKind::if_(this.hir.tcx(), cond, + body_block, exit_block); + this.cfg.terminate(loop_block_end, source_info, term); // 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 diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 812900b6bec..a28bc5d6ce3 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -672,12 +672,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(guard.span); let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: cond, - switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![otherwise, arm_block], - }); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); Some(otherwise) } else { let source_info = self.source_info(candidate.span); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f268eda4c15..7e47e173c51 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -228,6 +228,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { let (values, targets, ret) = if switch_ty.sty == ty::TyBool { + static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)]; assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); @@ -236,7 +237,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &ConstVal::Bool(false) => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; - (BOOL_SWITCH_FALSE.clone(), vec![false_bb, true_bb], ret) + (From::from(BOOL_SWITCH_FALSE), vec![false_bb, true_bb], ret) } else { // The switch may be inexhaustive so we // add a catch all block @@ -323,12 +324,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // check the result let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt { - discr: Operand::Consume(eq_result), - switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![fail, block], - }); + self.cfg.terminate(eq_block, source_info, + TerminatorKind::if_(self.hir.tcx(), + Operand::Consume(eq_result), + block, fail)); vec![block, fail] } else { let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); @@ -372,12 +371,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch based on result let (false_bb, true_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: Operand::Consume(result), - switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![false_bb, true_bb], - }); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result), + true_bb, false_bb)); vec![true_bb, false_bb] } } @@ -400,12 +396,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch based on result let target_block = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: Operand::Consume(result), - switch_ty: self.hir.bool_ty(), - values: BOOL_SWITCH_FALSE.clone(), - targets: vec![fail_block, target_block] - }); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result), + target_block, fail_block)); target_block } From 6c19104c43303da0bdc8b53c73ab2c1c2945dd37 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 05:34:46 +0200 Subject: [PATCH 16/21] Fix build Additionally, revert unnecessary changes to ty::layout --- src/librustc/ty/layout.rs | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 46161c8838d..74f2692629c 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -382,25 +382,8 @@ impl Integer { } } - pub fn to_attr(&self, signed: bool) -> attr::IntType { - match (*self, signed) { - (I1, false) => attr::IntType::UnsignedInt(UintTy::U8), - (I8, false) => attr::IntType::UnsignedInt(UintTy::U8), - (I16, false) => attr::IntType::UnsignedInt(UintTy::U16), - (I32, false) => attr::IntType::UnsignedInt(UintTy::U32), - (I64, false) => attr::IntType::UnsignedInt(UintTy::U64), - (I128, false) => attr::IntType::UnsignedInt(UintTy::U128), - (I1, true) => attr::IntType::SignedInt(IntTy::I8), - (I8, true) => attr::IntType::SignedInt(IntTy::I8), - (I16, true) => attr::IntType::SignedInt(IntTy::I16), - (I32, true) => attr::IntType::SignedInt(IntTy::I32), - (I64, true) => attr::IntType::SignedInt(IntTy::I64), - (I128, true) => attr::IntType::SignedInt(IntTy::I128), - } - } - /// Find the smallest Integer type which can represent the signed value. - pub fn fit_signed(x: i128) -> Integer { + pub fn fit_signed(x: i64) -> Integer { match x { -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1, -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, @@ -412,7 +395,7 @@ impl Integer { } /// Find the smallest Integer type which can represent the unsigned value. - pub fn fit_unsigned(x: u128) -> Integer { + pub fn fit_unsigned(x: u64) -> Integer { match x { 0...0x0000_0000_0000_0001 => I1, 0...0x0000_0000_0000_00ff => I8, @@ -453,13 +436,13 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - pub fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i128, max: i128) + fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) -> (Integer, bool) { // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there // are any negative values, the only valid unsigned representation is u64 // which can fit all i64 values, so the result remains unaffected. - let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); + let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64)); let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); let mut min_from_extern = None; @@ -487,6 +470,7 @@ impl Integer { } let at_least = min_from_extern.unwrap_or(min_default); + // If there are no negative values, we can use the unsigned fit. if min >= 0 { (cmp::max(unsigned_fit, at_least), false) @@ -1198,13 +1182,7 @@ impl<'a, 'gcx, 'tcx> Layout { i64::min_value(), true); for v in &def.variants { - let x = match def.discr_ty { - attr::IntType::SignedInt(IntTy::I128) | - attr::IntType::UnsignedInt(UintTy::U128) => - bug!("128-bit discriminants not yet supported"), - attr::IntType::SignedInt(_) => v.disr_val as i64, - attr::IntType::UnsignedInt(_) => v.disr_val as u64 as i64, - }; + let x = v.disr_val as i128 as i64; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } @@ -1212,7 +1190,9 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME: should handle i128? signed-value based impl is weird and hard to // grok. - let (discr, signed) = Integer::repr_discr(tcx, ty, hints, min, max); + let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], + min, + max); return success(CEnum { discr: discr, signed: signed, @@ -1330,6 +1310,7 @@ impl<'a, 'gcx, 'tcx> Layout { let discr_max = (variants.len() - 1) as i64; assert!(discr_max >= 0); let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max); + let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); From 1949bdf53196a2e6cac5d968523256ec1423cc1e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 22:03:36 +0200 Subject: [PATCH 17/21] Fix tests --- src/test/compile-fail/E0081.rs | 6 +++--- src/test/compile-fail/issue-15524.rs | 18 +++++++++--------- src/test/ui/custom-derive/issue-36935.stderr | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/test/compile-fail/E0081.rs b/src/test/compile-fail/E0081.rs index 9911e093a89..e12eff72c7f 100644 --- a/src/test/compile-fail/E0081.rs +++ b/src/test/compile-fail/E0081.rs @@ -9,10 +9,10 @@ // except according to those terms. enum Enum { - P = 3, //~ NOTE first use of `3isize` + P = 3, //~ NOTE first use of `3` X = 3, - //~^ ERROR discriminant value `3isize` already exists - //~| NOTE enum already has `3isize` + //~^ ERROR discriminant value `3` already exists + //~| NOTE enum already has `3` Y = 5 } diff --git a/src/test/compile-fail/issue-15524.rs b/src/test/compile-fail/issue-15524.rs index 658a0c1546b..0d5f5fd75eb 100644 --- a/src/test/compile-fail/issue-15524.rs +++ b/src/test/compile-fail/issue-15524.rs @@ -12,20 +12,20 @@ const N: isize = 1; enum Foo { A = 1, - //~^ NOTE first use of `1isize` - //~| NOTE first use of `1isize` - //~| NOTE first use of `1isize` + //~^ NOTE first use of `1` + //~| NOTE first use of `1` + //~| NOTE first use of `1` B = 1, - //~^ ERROR discriminant value `1isize` already exists - //~| NOTE enum already has `1isize` + //~^ ERROR discriminant value `1` already exists + //~| NOTE enum already has `1` C = 0, D, - //~^ ERROR discriminant value `1isize` already exists - //~| NOTE enum already has `1isize` + //~^ ERROR discriminant value `1` already exists + //~| NOTE enum already has `1` E = N, - //~^ ERROR discriminant value `1isize` already exists - //~| NOTE enum already has `1isize` + //~^ ERROR discriminant value `1` already exists + //~| NOTE enum already has `1` } diff --git a/src/test/ui/custom-derive/issue-36935.stderr b/src/test/ui/custom-derive/issue-36935.stderr index 9a5e2de14e3..46cc7a42b04 100644 --- a/src/test/ui/custom-derive/issue-36935.stderr +++ b/src/test/ui/custom-derive/issue-36935.stderr @@ -1,7 +1,7 @@ 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 From 49ccc106da350ecc9c5dd6540f3c7e5d51caa2c8 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 4 Feb 2017 03:55:56 +0200 Subject: [PATCH 18/21] Rebase fixups --- src/Cargo.lock | 1 - src/librustc/ty/mod.rs | 2 -- src/librustc_typeck/Cargo.toml | 1 - src/librustc_typeck/lib.rs | 2 -- src/test/codegen/match.rs | 2 +- src/test/mir-opt/simplify_if.rs | 2 +- 6 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 8b76381a586..09aefd45e94 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -578,7 +578,6 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", - "rustc_i128 0.0.0", "rustc_platform_intrinsics 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 523c61d404f..411e14531fa 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -71,8 +71,6 @@ pub use self::context::{Lift, TypeckTables}; pub use self::trait_def::{TraitDef, TraitFlags}; -use rustc_i128::u128; - pub mod adjustment; pub mod cast; pub mod error; diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 06789355242..f08d26373e5 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -22,4 +22,3 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } -rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index aa2695b9553..f19a59a5d38 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -98,8 +98,6 @@ extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors as errors; -extern crate rustc_i128; - pub use rustc::dep_graph; pub use rustc::hir; pub use rustc::lint; diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs index c35206e6e0a..aa100da6013 100644 --- a/src/test/codegen/match.rs +++ b/src/test/codegen/match.rs @@ -21,7 +21,7 @@ pub enum E { #[no_mangle] pub fn exhaustive_match(e: E) { // CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [ -// CHECK-NEXT: i8 [[DISCR:[0-9]+]], label %[[TRUE:[a-zA-Z0-9_]+]] +// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[TRUE:[a-zA-Z0-9_]+]] // CHECK-NEXT: ] // CHECK: [[TRUE]]: // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]] diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 7239e32357b..0e8971269b0 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyBranches.initial-before.mir // bb0: { -// if(const false) -> [true: bb1, false: bb2]; +// switchInt(const false) -> [0: bb2, otherwise: bb1]; // } // END rustc.node4.SimplifyBranches.initial-before.mir // START rustc.node4.SimplifyBranches.initial-after.mir From 7d1f36a482fed39ea5989bf971464622b8cba89e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 5 Feb 2017 01:09:55 +0200 Subject: [PATCH 19/21] Inline open_drop_for_variant & clean matches::test --- .../borrowck/mir/elaborate_drops.rs | 65 +++++++------------ src/librustc_mir/build/matches/test.rs | 21 +++--- 2 files changed, 32 insertions(+), 54 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index d7ffe538c24..5899c9f31d1 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -620,48 +620,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.elaborated_drop_block(&inner_c) } - fn open_drop_for_variant<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - drop_block: &mut Option, - adt: &'tcx ty::AdtDef, - substs: &'tcx Substs<'tcx>, - variant_index: usize) - -> (BasicBlock, bool) - { - 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), true) - } else { - // variant not found - drop the entire enum - if let None = *drop_block { - *drop_block = Some(self.complete_drop(c, true)); - } - (drop_block.unwrap(), false) - } - } - fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) -> BasicBlock { debug!("open_drop_for_adt({:?}, {:?}, {:?})", c, adt, substs); - let mut drop_block = None; - match adt.variants.len() { 1 => { let fields = self.move_paths_for_fields( @@ -676,17 +639,33 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let mut values = Vec::with_capacity(adt.variants.len()); let mut blocks = Vec::with_capacity(adt.variants.len()); let mut otherwise = None; - for (idx, variant) in adt.variants.iter().enumerate() { + for (variant_index, variant) in adt.variants.iter().enumerate() { 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 (blk, is_ladder) = self.open_drop_for_variant(c, &mut drop_block, adt, - substs, idx); - if is_ladder { + 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(blk); + blocks.push(self.drop_ladder(c, fields)); } else { - otherwise = Some(blk) + // variant not found - drop the entire enum + if let None = otherwise { + otherwise = Some(self.complete_drop(c, true)); + } } } if let Some(block) = otherwise { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 7e47e173c51..01c0433112b 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -227,8 +227,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { - let (values, targets, ret) = if switch_ty.sty == ty::TyBool { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)]; + let (ret, terminator) = if switch_ty.sty == ty::TyBool { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); @@ -237,7 +236,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &ConstVal::Bool(false) => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; - (From::from(BOOL_SWITCH_FALSE), vec![false_bb, true_bb], ret) + (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()), + true_bb, false_bb)) } else { // The switch may be inexhaustive so we // add a catch all block @@ -250,15 +250,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let values: Vec<_> = options.iter().map(|v| v.to_const_int().expect("switching on integral") ).collect(); - (From::from(values), targets.clone(), targets) + (targets.clone(), TerminatorKind::SwitchInt { + discr: Operand::Consume(lvalue.clone()), + switch_ty: switch_ty, + values: From::from(values), + targets: targets, + }) }; - - self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { - discr: Operand::Consume(lvalue.clone()), - switch_ty: switch_ty, - values: values, - targets: targets.clone(), - }); + self.cfg.terminate(block, source_info, terminator); ret } From f3bd7231015706bee72846a758e1234febaaa60a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 10 Feb 2017 19:29:39 +0200 Subject: [PATCH 20/21] Fix intcast, use it where appropriate --- src/librustc/ty/layout.rs | 18 +++++++++++++++++- src/librustc_llvm/ffi.rs | 10 +++++----- src/librustc_trans/adt.rs | 2 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/builder.rs | 4 ++-- src/librustc_trans/mir/rvalue.rs | 14 ++------------ src/rustllvm/RustWrapper.cpp | 6 ++++++ 7 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 74f2692629c..6a2fdc6aab6 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1310,7 +1310,6 @@ impl<'a, 'gcx, 'tcx> Layout { let discr_max = (variants.len() - 1) as i64; assert!(discr_max >= 0); let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max); - let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); @@ -1351,6 +1350,23 @@ impl<'a, 'gcx, 'tcx> Layout { 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 // discriminant. We can safely use a type with the same size // as the alignment of the first field of each variant. diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 5273910d1d9..8e2e072b584 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1084,11 +1084,11 @@ extern "C" { DestTy: TypeRef, Name: *const c_char) -> ValueRef; - pub fn LLVMBuildIntCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; + pub fn LLVMRustBuildIntCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + IsSized: bool) + -> ValueRef; pub fn LLVMBuildFPCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 59f2104ec14..11d3fae8238 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -318,7 +318,7 @@ pub fn trans_get_discr<'a, 'tcx>( }; match cast_to { 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)) } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ce02c9725d1..41c0eaa52a7 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -536,7 +536,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>, let memcpy = ccx.get_intrinsic(&key); let src_ptr = b.pointercast(src, 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 volatile = C_bool(ccx, false); b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 89aaa8b6630..f64e581c177 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -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"); unsafe { - llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed) } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 2eb4ea6cedd..38ee67796c6 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -286,17 +286,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let newval = match (r_t_in, r_t_out) { (CastTy::Int(_), CastTy::Int(_)) => { - let srcsz = ll_t_in.int_width(); - 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) - } + bcx.intcast(llval, ll_t_out, signed) } (CastTy::Float, CastTy::Float) => { let srcsz = ll_t_in.float_width(); @@ -439,7 +429,7 @@ impl<'a, 'tcx> MirContext<'a, '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, - Some(discr_type), true); + discr_lvalue.alignment, Some(discr_type), true); (bcx, OperandRef { val: OperandValue::Immediate(discr), ty: discr_ty diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 27233a8b075..c15a0c3d25a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1308,6 +1308,12 @@ extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef 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, LLVMRustVisibility RustVisibility) { LLVMSetVisibility(V, fromRust(RustVisibility)); From b663d9d5e85c06ca980e75c545fadc51226ab38c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 10 Feb 2017 20:19:32 +0200 Subject: [PATCH 21/21] Rebase fallout Because certain somebody sucks at resolving big conflicts --- src/librustc/ty/layout.rs | 6 ++---- src/librustc_metadata/decoder.rs | 6 +++--- src/librustc_metadata/encoder.rs | 3 ++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6a2fdc6aab6..f429053d8bb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1190,9 +1190,7 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME: should handle i128? signed-value based impl is weird and hard to // grok. - let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], - min, - max); + let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); return success(CEnum { discr: discr, signed: signed, @@ -1309,7 +1307,7 @@ impl<'a, 'gcx, 'tcx> Layout { // The general case. let discr_max = (variants.len() - 1) as i64; assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max); + let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max); let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 88c04d88a6f..abc3ffcf86b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -546,12 +546,12 @@ impl<'a, 'tcx> CrateMetadata { 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), + 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 variants = if let EntryKind::Enum(_) = item.kind { + let variants = if let ty::AdtKind::Enum = kind { item.children .decode(self) .map(|index| { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b913f68e584..0f9491aaf15 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -661,7 +661,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemForeignMod(_) => EntryKind::ForeignMod, hir::ItemTy(..) => EntryKind::Type, - hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty), 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, _) => { let variant = tcx.lookup_adt_def(def_id).struct_variant();