From ba60af3bbdde527c7944e67218bff4c6b283ad3b Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Mon, 21 Nov 2016 20:19:52 -0500 Subject: [PATCH 01/29] Document RFC 1623: static lifetime elision. --- src/doc/reference.md | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 9898c31282c34..713e6f1ab99eb 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1271,7 +1271,8 @@ guaranteed to refer to the same memory address. Constant values must not have destructors, and otherwise permit most forms of data. Constants may refer to the address of other constants, in which case the -address will have the `static` lifetime. The compiler is, however, still at +address will have the `static` lifetime. (See below on [static lifetime +elision](#static-lifetime-elision).) The compiler is, however, still at liberty to translate the constant many times, so the address referred to may not be stable. @@ -1279,7 +1280,7 @@ Constants must be explicitly typed. The type may be `bool`, `char`, a number, or a type derived from those primitive types. The derived types are references with the `static` lifetime, fixed-size arrays, tuples, enum variants, and structs. -``` +```rust const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; @@ -1331,7 +1332,7 @@ running in the same process. Mutable statics are still very useful, however. They can be used with C libraries and can also be bound from C libraries (in an `extern` block). -``` +```rust # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } static mut LEVELS: u32 = 0; @@ -1355,6 +1356,31 @@ unsafe fn bump_levels_unsafe2() -> u32 { Mutable statics have the same restrictions as normal statics, except that the type of the value is not required to ascribe to `Sync`. +#### `'static` lifetime elision + +Both constant and static declarations of reference types have *implicit* +`'static` lifetimes unless an explicit lifetime is specified. As such, the +constant declarations involving `'static` above may be written without the +lifetimes. Returning to our previous example: + +```rust +const BIT1: u32 = 1 << 0; +const BIT2: u32 = 1 << 1; + +const BITS: [u32; 2] = [BIT1, BIT2]; +const STRING: &str = "bitstring"; + +struct BitsNStrings<'a> { + mybits: [u32; 2], + mystring: &'a str, +} + +const BITS_N_STRINGS: BitsNStrings = BitsNStrings { + mybits: BITS, + mystring: STRING, +}; +``` + ### Traits A _trait_ describes an abstract interface that types can @@ -2458,9 +2484,6 @@ The currently implemented features of the reference compiler are: into a Rust program. This capability, especially the signature for the annotated function, is subject to change. -* `static_in_const` - Enables lifetime elision with a `'static` default for - `const` and `static` item declarations. - * `thread_local` - The usage of the `#[thread_local]` attribute is experimental and should be seen as unstable. This attribute is used to declare a `static` as being unique per-thread leveraging From e8cb83a8237d79f4c8523f4b8df5e73688cfb8bb Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Sat, 28 Jan 2017 09:42:32 -0500 Subject: [PATCH 02/29] Add feature flag to reference docs for RFC 1623. --- src/doc/reference.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 713e6f1ab99eb..c6fc2ea40590c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1356,7 +1356,7 @@ unsafe fn bump_levels_unsafe2() -> u32 { Mutable statics have the same restrictions as normal statics, except that the type of the value is not required to ascribe to `Sync`. -#### `'static` lifetime elision +#### `'static` lifetime elision [unstable] Both constant and static declarations of reference types have *implicit* `'static` lifetimes unless an explicit lifetime is specified. As such, the @@ -1364,6 +1364,7 @@ constant declarations involving `'static` above may be written without the lifetimes. Returning to our previous example: ```rust +#[feature(static_in_const)] const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; From 3f0ca5578051f67046abb04d053118439b162f87 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Sat, 28 Jan 2017 12:45:54 -0500 Subject: [PATCH 03/29] Change placement of `[Unstable]` marker in RFC 1623 docs. --- src/doc/reference.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index c6fc2ea40590c..dd3ccb82211f5 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1356,12 +1356,12 @@ unsafe fn bump_levels_unsafe2() -> u32 { Mutable statics have the same restrictions as normal statics, except that the type of the value is not required to ascribe to `Sync`. -#### `'static` lifetime elision [unstable] +#### `'static` lifetime elision -Both constant and static declarations of reference types have *implicit* -`'static` lifetimes unless an explicit lifetime is specified. As such, the -constant declarations involving `'static` above may be written without the -lifetimes. Returning to our previous example: +[Unstable] Both constant and static declarations of reference types have +*implicit* `'static` lifetimes unless an explicit lifetime is specified. As +such, the constant declarations involving `'static` above may be written +without the lifetimes. Returning to our previous example: ```rust #[feature(static_in_const)] From c68e9632db0bac369dea6cd2206b9119aab83d2e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 31 Jan 2017 01:10:54 +0200 Subject: [PATCH 04/29] 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 6e9091cf31728..64642249f965d 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 f1268521d6708..68fbadd5d6065 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 b5da304a10986..921b4e78b32c9 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 7cf6ab2999c05..806395c857a88 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 9c1107344f241..16371be576b05 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 cec1c20519bd6..e29febdb712d3 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 81b241b485175..74df3428b99e3 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -429,6 +429,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); @@ -657,6 +675,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 caf9f95f4699b7c1a83b7567b01870365e52e20c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 31 Jan 2017 05:32:08 +0200 Subject: [PATCH 05/29] 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 | 12 +----- src/test/ui/custom-derive/issue-36935.rs | 1 + 18 files changed, 76 insertions(+), 101 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 64642249f965d..80ef6fdd95214 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 921b4e78b32c9..1e27a02287fd1 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 f11cf90834dd9..8dd591fa2e778 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 d2f744bde2d63..45f534767e4e7 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 806395c857a88..9e7e5ec9ee861 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 3d4af259ec9f7..2b4336ba66f07 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 5c3d93ffda9c1..0898d06d2e470 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 a35b2925ae271..291bd65d57775 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 01dc01c5ecfd4..4ac67cfb2fca1 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 6ef5720b330c9..425df65659c6f 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 16371be576b05..bda4c94625f8b 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 d5fc90289e2cc..1127f50fe508c 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 8759a340d7e3c..424250586b162 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 529fe564af02b..9d2ad31438658 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 e29febdb712d3..fef61128d04e5 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 2a1ab10d74e16..97118a7206299 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 027779aca63e4..773e2bc871026 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()); @@ -178,9 +170,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 discr = bcx.load(self.trans_lvalue(&bcx, discr).llval); - 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 22d603563de17..2231c3c242285 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 6849985babf731d82e1f41790828b8b86e016b48 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 1 Feb 2017 03:38:28 +0200 Subject: [PATCH 06/29] 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 | 22 +++-- 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, 99 insertions(+), 132 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a0eae33c4402b..633b6c1747c0c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -672,9 +672,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn alloc_adt_def(self, did: DefId, kind: AdtKind, + discr_ty: Option, variants: Vec) -> &'gcx ty::AdtDef { - let def = ty::AdtDef::new(self, did, kind, variants); + let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8)); + let def = ty::AdtDef::new(self, did, kind, discr_ty, variants); self.global_arenas.adt_def.alloc(def) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ff3ac3586a787..4697726841589 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; 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; @@ -1207,10 +1206,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; } @@ -1271,7 +1272,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 c9ae3b3df028c..faadae4fec205 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 @@ -1360,6 +1362,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, did: DefId, kind: AdtKind, + discr_ty: attr::IntType, variants: Vec) -> Self { let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); @@ -1382,6 +1385,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 b01b77bbcf8a5..1df87da42274c 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 f4a35ea5fd0cf..39bbff08f5b93 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,8 +544,14 @@ 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 { + let variants = if let ty::AdtKind::Enum = kind { item.children .decode(self) .map(|index| { @@ -561,14 +565,8 @@ impl<'a, 'tcx> CrateMetadata { ctor_index = struct_ctor; vec![variant] }; - let kind = match item.kind { - EntryKind::Enum => ty::AdtKind::Enum, - EntryKind::Struct(_) => ty::AdtKind::Struct, - EntryKind::Union(_) => ty::AdtKind::Union, - _ => bug!("get_adt_def called on a non-ADT {:?}", did), - }; - let adt = tcx.alloc_adt_def(did, kind, variants); + let adt = tcx.alloc_adt_def(did, kind, ty, variants); 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 69e1bbd77662b..6670be64c26ec 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), }; @@ -659,7 +659,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemForeignMod(_) => EntryKind::ForeignMod, hir::ItemTy(..) => EntryKind::Type, - hir::ItemEnum(..) => EntryKind::Enum, + hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty)), hir::ItemStruct(ref struct_def, _) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); @@ -673,7 +673,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, })) } @@ -682,7 +682,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, })) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d13628e9ce7a3..0ee42aa1bb2c8 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, + Enum(Lazy), Field, Variant(Lazy), Struct(Lazy), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index c83e2f4854bf5..1adfebe712363 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 c5737c6e5f12c..f3a62bc85b8d9 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 266975994ec3a..a0c852ad531ec 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); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt); @@ -1022,63 +1021,63 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> &'tcx ty::AdtDef { let did = ccx.tcx.hir.local_def_id(it.id); - let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants); + let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)]; + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants); 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)); - - 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(); - }; +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 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, @@ -1092,7 +1091,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) { @@ -1112,7 +1111,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants); + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants); tcx.adt_defs.borrow_mut().insert(did, adt); adt } From a8075a440c4154afd278bae095bd45173357332b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 1 Feb 2017 05:10:35 +0200 Subject: [PATCH 07/29] AdtDef now contains discr_ty same as layouted --- src/Cargo.lock | 1 + src/librustc/ty/layout.rs | 40 ++++++++++++++++++++++------------ src/librustc_typeck/Cargo.toml | 1 + src/librustc_typeck/collect.rs | 12 +++++++--- src/librustc_typeck/lib.rs | 2 ++ 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 06cf32ad0f6b5..1189bc40faca4 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -529,6 +529,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 4697726841589..8ff0be4856f4f 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,13 +453,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. - fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64) - -> (Integer, bool) { + pub fn repr_discr(tcx: TyCtxt, hints: &[attr::ReprAttr], 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 // 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; @@ -455,7 +472,7 @@ impl Integer { 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 `{}", ty) + discriminant range of enum") } return (discr, ity.is_signed()); } @@ -471,16 +488,15 @@ impl Integer { } attr::ReprAny => {}, attr::ReprPacked => { - bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty); + bug!("Integer::repr_discr: found #[repr(packed)] on enum"); } attr::ReprSimd => { - bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty); + bug!("Integer::repr_discr: found #[repr(simd)] on enum"); } } } 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) @@ -1220,9 +1236,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, &hints[..], - 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, @@ -1337,10 +1352,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::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 f08d26373e50e..067893552427b 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 a0c852ad531ec..a8062ed845ff8 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}; -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 @@ -1090,9 +1092,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) @@ -1106,12 +1110,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(); - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants); + let (repr_int, signed) = layout::Integer::repr_discr(tcx, &repr_hints[..], min, max); + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_int.to_attr(signed)), variants); tcx.adt_defs.borrow_mut().insert(did, adt); adt } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index f19a59a5d38ae..aa2695b9553e7 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 1355a575447e36b7a5c512a622066a2412552f7b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 02:05:56 +0200 Subject: [PATCH 08/29] 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 | 36 ------------- 19 files changed, 105 insertions(+), 128 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index f583f601726ed..c4e3827fef289 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 80ef6fdd95214..e9769efb36beb 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 68fbadd5d6065..fcfd1c5767216 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 1e27a02287fd1..ca20cf6236b58 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 1df87da42274c..fe4b6dad30e04 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 8dd591fa2e778..8b246105f6169 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 45f534767e4e7..8f3dcd0b8d673 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 9e7e5ec9ee861..0c7e922c48ab4 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 17714f2fb2d6c..bc3809db1c63a 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 3700d46c3462a..ffcd25a4cdd39 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 291bd65d57775..528e37e73c4f3 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 61ba9d90fef38..9a8fb1099d04b 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 425df65659c6f..55a26f4b37fe2 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 bda4c94625f8b..922521726c626 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 1127f50fe508c..e93a412dc744f 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 9d2ad31438658..8ede7aaab5f68 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 fef61128d04e5..517a472056334 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 97118a7206299..37725bfa2de84 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 773e2bc871026..a56c10b565652 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}; 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,39 +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, 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 94e587ef296492acf767cf2d39a22d3138f00a25 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 06:44:30 +0200 Subject: [PATCH 09/29] 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 c4e3827fef289..f885a6d95693f 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 e9769efb36beb..9957f8c5e9e28 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 ca20cf6236b58..be3c43db7badd 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_int(&mut self, _const_int: &ConstInt) { } - fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) { + 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 8f3dcd0b8d673..53e84f1fb7117 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 2b4336ba66f07..537daa4a15ba4 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 0898d06d2e470..885965da1f924 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 528e37e73c4f3..f2d48f65fef2f 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 a56c10b565652..6b3081f610060 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}; 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 f92faaa0508a6..199188bf0ab3c 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -60,6 +60,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, @@ -71,26 +98,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 ba39fcdec6f88..c6847249803e3 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 339358416e8458b96f158d47e7686a979b47d46e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 07:25:29 +0200 Subject: [PATCH 10/29] 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 8ff0be4856f4f..a18152e75e938 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 76bc6c31aa3c73669b8664094059fb829b47f789 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 08:41:01 +0200 Subject: [PATCH 11/29] 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 424250586b162..3d5106c4b06f7 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 cd4147942dd2da5dbe3c962428b06d525f5fab4f Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 19:53:44 +0200 Subject: [PATCH 12/29] Fix the IntTypeExt::to_ty() lifetime bounds --- src/librustc/mir/tcx.rs | 10 ++-------- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/util.rs | 4 ++-- src/librustc_borrowck/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(+), 23 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index fcfd1c5767216..6863468ec0d5b 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 a18152e75e938..6e25ce200720b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -454,7 +454,7 @@ impl Integer { /// 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, hints: &[attr::ReprAttr], min: i128, max: i128) - -> (Integer, bool) { + -> (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 diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fe4b6dad30e04..0281e53427d6d 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 53e84f1fb7117..7521b750d5a09 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 f2d48f65fef2f..d9c2e6bb09071 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 74df3428b99e3..259f02a044c12 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -434,7 +434,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 a8062ed845ff8..d1041f89b723d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1045,7 +1045,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 ff167a6a2ac34ca174c48cf3c249894991d1e065 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 20:35:54 +0200 Subject: [PATCH 13/29] 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 9957f8c5e9e28..bcd34eaf54e8c 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 6863468ec0d5b..7b0863b4c42bc 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 7521b750d5a09..144b0c2203ab7 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 4e7770e4c2dc0985a85de7f8877bdb284a89bc64 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 22:03:23 +0200 Subject: [PATCH 14/29] 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 f885a6d95693f..11919db479c1a 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 bcd34eaf54e8c..19a6682b1c7be 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 144b0c2203ab7..44b85c31d8644 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 537daa4a15ba4..f61b4a6607722 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 885965da1f924..812900b6becc7 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 d9c2e6bb09071..f268eda4c15a5 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 d3f704a3bee191b095d7f35cb171c17576fbceb3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 2 Feb 2017 22:53:21 +0200 Subject: [PATCH 15/29] 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 ac47f6082e3e3..c35206e6e0a45 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 5e465d52e603b8486c2a497dc3baffb0cd272993 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 00:07:31 +0200 Subject: [PATCH 16/29] 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 37725bfa2de84..2c3b479c7dd0f 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 1fee7221050642d8ed82b1d192c12847f3311071 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 02:34:29 +0200 Subject: [PATCH 17/29] Revert use of layout code in typeck::collect --- src/librustc/ty/layout.rs | 13 +++++++------ src/librustc/ty/mod.rs | 7 ++++++- src/librustc/ty/util.rs | 18 ------------------ src/librustc_trans/mir/rvalue.rs | 8 ++------ src/librustc_typeck/collect.rs | 28 ++++++++++++---------------- 5 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6e25ce200720b..02da7529ed39a 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. - pub fn repr_discr(tcx: TyCtxt, hints: &[attr::ReprAttr], min: i128, max: i128) + pub fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], 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 @@ -488,10 +488,10 @@ impl Integer { } attr::ReprAny => {}, attr::ReprPacked => { - bug!("Integer::repr_discr: found #[repr(packed)] on enum"); + bug!("Integer::repr_discr: found #[repr(packed)] on enum {}", ty); } attr::ReprSimd => { - bug!("Integer::repr_discr: found #[repr(simd)] on enum"); + bug!("Integer::repr_discr: found #[repr(simd)] on enum {}", ty); } } } @@ -1236,8 +1236,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, @@ -1352,7 +1351,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 faadae4fec205..195d7e960eb5d 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 0281e53427d6d..16492de6c3d27 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 259f02a044c12..6874a0245b0b9 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -434,12 +434,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 d1041f89b723d..31f2af9b15c6b 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}; -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 @@ -1030,7 +1028,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)); @@ -1060,7 +1058,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 @@ -1091,15 +1089,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, @@ -1111,14 +1111,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 (repr_int, signed) = layout::Integer::repr_discr(tcx, &repr_hints[..], min, max); - 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); tcx.adt_defs.borrow_mut().insert(did, adt); adt } From 832d7e07b099c12c507d8476784170a95d1c5f59 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 03:36:32 +0200 Subject: [PATCH 18/29] 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 19a6682b1c7be..9127d96ad4272 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 44b85c31d8644..d7ffe538c2456 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 f61b4a6607722..35841c2cbdf01 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 812900b6becc7..a28bc5d6ce36d 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 f268eda4c15a5..7e47e173c51c5 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 4e29e816a3f5eddae2f168ef569d56b3646bbdc9 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 05:34:46 +0200 Subject: [PATCH 19/29] Fix build Additionally, revert unnecessary changes to ty::layout --- src/librustc/ty/layout.rs | 45 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 02da7529ed39a..b21e6492dbce5 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, hints: &[attr::ReprAttr], min: i128, max: i128) + fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], 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; @@ -472,7 +455,7 @@ impl Integer { 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") + discriminant range of enum `{}", ty) } return (discr, ity.is_signed()); } @@ -488,15 +471,16 @@ impl Integer { } attr::ReprAny => {}, attr::ReprPacked => { - bug!("Integer::repr_discr: found #[repr(packed)] on enum {}", ty); + bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty); } attr::ReprSimd => { - bug!("Integer::repr_discr: found #[repr(simd)] on enum {}", ty); + bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty); } } } 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) @@ -1222,13 +1206,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; } @@ -1236,7 +1214,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, @@ -1354,6 +1334,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 cdd4aadb8a987ce6854a9af1225e4d35e41a89d6 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Feb 2017 22:03:36 +0200 Subject: [PATCH 20/29] 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 9911e093a8980..e12eff72c7f41 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 658a0c1546b9f..0d5f5fd75eba8 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 9a5e2de14e3b0..46cc7a42b0429 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 1e8c855de6453521579a87994d3a6484dfd04b6c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 4 Feb 2017 03:55:56 +0200 Subject: [PATCH 21/29] 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 1189bc40faca4..06cf32ad0f6b5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -529,7 +529,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 195d7e960eb5d..a292d7c032d55 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 067893552427b..f08d26373e50e 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 aa2695b9553e7..f19a59a5d38ae 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 c35206e6e0a45..aa100da60132f 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 7239e32357b95..0e8971269b007 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 1246779f743d2df9d1f1619dc789e79035a6280d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 5 Feb 2017 01:09:55 +0200 Subject: [PATCH 22/29] 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 d7ffe538c2456..5899c9f31d14d 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 7e47e173c51c5..01c0433112bf3 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 7c2752a95be8878ccda118e4536c2d14363d45e4 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Mon, 6 Feb 2017 18:03:26 +0100 Subject: [PATCH 23/29] rustbuild: support setting verbosity in config.toml Signed-off-by: Marc-Antoine Perennou --- src/bootstrap/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6e077691b3a05..aa2bc38143d5c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -148,6 +148,7 @@ struct Build { python: Option, full_bootstrap: Option, extended: Option, + verbose: Option, } /// TOML representation of various global install decisions. @@ -292,6 +293,7 @@ impl Config { set(&mut config.vendor, build.vendor); set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); + set(&mut config.verbose, build.verbose); if let Some(ref install) = toml.install { config.prefix = install.prefix.clone().map(PathBuf::from); From 05eef36fa5ff9235ea8124a6396c7973015b4b8b Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 6 Feb 2017 17:50:30 +0000 Subject: [PATCH 24/29] rustdoc: Improve impl disambiguation * Don't disambiguate if there are multiple impls for the same type. * Disambiguate for impls of &Foo and &mut Foo. * Don't try to disambiguate generic types. --- src/librustdoc/html/format.rs | 6 ++-- src/librustdoc/html/render.rs | 32 ++++++++++++++------ src/test/rustdoc/impl-disambiguation.rs | 40 +++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/test/rustdoc/impl-disambiguation.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 60dae19d876c9..c591c09bf20e2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -671,9 +671,11 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt: } _ => { if f.alternate() { - write!(f, "&{}{}{:#}", lt, m, **ty) + write!(f, "&{}{}", lt, m)?; + fmt_type(&ty, f, use_absolute) } else { - write!(f, "&{}{}{}", lt, m, **ty) + write!(f, "&{}{}", lt, m)?; + fmt_type(&ty, f, use_absolute) } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 40eb7e5ab78c3..6234d89024441 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2132,10 +2132,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
    ")?; if let Some(implementors) = cache.implementors.get(&it.def_id) { - let mut implementor_count: FxHashMap<&str, usize> = FxHashMap(); + // The DefId is for the first Type found with that name. The bool is + // if any Types with the same name but different DefId have been found. + let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap(); for implementor in implementors { - if let clean::Type::ResolvedPath {ref path, ..} = implementor.impl_.for_ { - *implementor_count.entry(path.last_name()).or_insert(0) += 1; + match implementor.impl_.for_ { + clean::ResolvedPath { ref path, did, is_generic: false, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. }, + .. + } => { + let &mut (prev_did, ref mut has_duplicates) = + implementor_dups.entry(path.last_name()).or_insert((did, false)); + if prev_did != did { + *has_duplicates = true; + } + } + _ => {} } } @@ -2143,12 +2156,13 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "
  • ")?; // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` - let use_absolute = if let clean::Type::ResolvedPath { - ref path, .. - } = implementor.impl_.for_ { - implementor_count[path.last_name()] > 1 - } else { - false + let use_absolute = match implementor.impl_.for_ { + clean::ResolvedPath { ref path, is_generic: false, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, + .. + } => implementor_dups[path.last_name()].1, + _ => false, }; fmt_impl_for_trait_page(&implementor.impl_, w, use_absolute)?; writeln!(w, "
  • ")?; diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs new file mode 100644 index 0000000000000..afe1daf5983a2 --- /dev/null +++ b/src/test/rustdoc/impl-disambiguation.rs @@ -0,0 +1,40 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub trait Foo {} + +pub struct Bar { field: T } + +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for Bar" +impl Foo for Bar {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for Bar" +impl Foo for Bar {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl<'a> Foo for &'a Bar" +impl<'a> Foo for &'a Bar {} + +pub mod mod1 { + pub struct Baz {} +} + +pub mod mod2 { + pub enum Baz {} +} + +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for foo::mod1::Baz" +impl Foo for mod1::Baz {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl<'a> Foo for &'a foo::mod2::Baz" +impl<'a> Foo for &'a mod2::Baz {} From 4268872807cf8bc5c8c435794d1c82d21899d67b Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Mon, 6 Feb 2017 20:47:04 +0100 Subject: [PATCH 25/29] rustbuild: add verbose to config.toml.example Signed-off-by: Marc-Antoine Perennou --- src/bootstrap/config.toml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index a53419ad7fd78..42bc20c24e569 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -124,6 +124,9 @@ # disabled by default. #extended = false +# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose +#verbose = 0 + # ============================================================================= # General install configuration options # ============================================================================= From 52a887e12b2d5eaaedfee6843826960f4eee42a8 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 8 Feb 2017 10:56:42 +0100 Subject: [PATCH 26/29] Remove some leftover makefiles. --- mk/cfg/aarch64-unknown-freebsd.mk | 1 - mk/cfg/i686-unknown-netbsd.mk | 1 - 2 files changed, 2 deletions(-) delete mode 100644 mk/cfg/aarch64-unknown-freebsd.mk delete mode 100644 mk/cfg/i686-unknown-netbsd.mk diff --git a/mk/cfg/aarch64-unknown-freebsd.mk b/mk/cfg/aarch64-unknown-freebsd.mk deleted file mode 100644 index 34aee77ae2107..0000000000000 --- a/mk/cfg/aarch64-unknown-freebsd.mk +++ /dev/null @@ -1 +0,0 @@ -# rustbuild-only target diff --git a/mk/cfg/i686-unknown-netbsd.mk b/mk/cfg/i686-unknown-netbsd.mk deleted file mode 100644 index 34aee77ae2107..0000000000000 --- a/mk/cfg/i686-unknown-netbsd.mk +++ /dev/null @@ -1 +0,0 @@ -# rustbuild-only target From 4096dd684c5f11dea5bd231a97adfb7205a82213 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Wed, 8 Feb 2017 14:30:31 -0500 Subject: [PATCH 27/29] Add more examples, get everything passing at last. --- src/doc/reference.md | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index dd3ccb82211f5..4910313af9303 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1271,10 +1271,12 @@ guaranteed to refer to the same memory address. Constant values must not have destructors, and otherwise permit most forms of data. Constants may refer to the address of other constants, in which case the -address will have the `static` lifetime. (See below on [static lifetime -elision](#static-lifetime-elision).) The compiler is, however, still at -liberty to translate the constant many times, so the address referred to may not -be stable. +address will have elided lifetimes where applicable, otherwise – in most cases – +defaulting to the `static` lifetime. (See below on [static lifetime elision].) +The compiler is, however, still at liberty to translate the constant many times, +so the address referred to may not be stable. + +[static lifetime elision]: #static-lifetime-elision Constants must be explicitly typed. The type may be `bool`, `char`, a number, or a type derived from those primitive types. The derived types are references with @@ -1298,6 +1300,8 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` + + ### Static items A *static item* is similar to a *constant*, except that it represents a precise @@ -1364,7 +1368,7 @@ such, the constant declarations involving `'static` above may be written without the lifetimes. Returning to our previous example: ```rust -#[feature(static_in_const)] +# #![feature(static_in_const)] const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; @@ -1382,6 +1386,27 @@ const BITS_N_STRINGS: BitsNStrings = BitsNStrings { }; ``` +Note that if the `static` or `const` items include function or closure +references, which themselves include references, the compiler will first try the +standard elision rules ([see discussion in the nomicon][elision-nomicon]). If it +is unable to resolve the lifetimes by its usual rules, it will default to using +the `'static` lifetime. By way of example: + +[elision-nomicon]: https://doc.rust-lang.org/nomicon/lifetime-elision.html + +```rust,ignore +// Resolved as `fn<'a>(&'a str) -> &'a str`. +const RESOLVED_SINGLE: fn(&str) -> &str = .. + +// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`. +const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = .. + +// There is insufficient information to bound the return reference lifetime +// relative to the argument lifetimes, so the signature is resolved as +// `Fn(&'static Foo, &'static Bar) -> &'static Baz`. +const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = .. +``` + ### Traits A _trait_ describes an abstract interface that types can @@ -2079,7 +2104,9 @@ macro scope. ### Miscellaneous attributes -- `deprecated` - mark the item as deprecated; the full attribute is `#[deprecated(since = "crate version", note = "...")`, where both arguments are optional. +- `deprecated` - mark the item as deprecated; the full attribute is + `#[deprecated(since = "crate version", note = "...")`, where both arguments + are optional. - `export_name` - on statics and functions, this determines the name of the exported symbol. - `link_section` - on statics and functions, this specifies the section of the From 3022614ec3c602a5812286c855633ea34683b038 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Feb 2017 18:42:01 +0100 Subject: [PATCH 28/29] Add missing urls on join_paths --- src/libstd/env.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index e264153929491..1ef2cb4ed153c 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -400,15 +400,19 @@ pub struct JoinPathsError { inner: os_imp::JoinPathsError } -/// Joins a collection of `Path`s appropriately for the `PATH` +/// Joins a collection of [`Path`]s appropriately for the `PATH` /// environment variable. /// -/// Returns an `OsString` on success. +/// Returns an [`OsString`] on success. /// -/// Returns an `Err` (containing an error message) if one of the input -/// `Path`s contains an invalid character for constructing the `PATH` +/// Returns an [`Err`][err] (containing an error message) if one of the input +/// [`Path`]s contains an invalid character for constructing the `PATH` /// variable (a double quote on Windows or a colon on Unix). /// +/// [`Path`]: ../../std/path/struct.Path.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html +/// [err]: ../../std/result/enum.Result.html#variant.Err +/// /// # Examples /// /// ``` From 51ef003deaf2ac82edeeb03a98630330b069817a Mon Sep 17 00:00:00 2001 From: Henning Kowalk Date: Thu, 9 Feb 2017 00:44:36 +0100 Subject: [PATCH 29/29] Fixed #39661 Clarified potential ambiguity. --- src/libstd/collections/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index b9e92a01b2f8e..4fae9fcb51c4e 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -68,7 +68,7 @@ //! * You want to find the largest or smallest key that is smaller or larger //! than something. //! * You want to be able to get all of the entries in order on-demand. -//! * You want a sorted map. +//! * You want map sorted by its keys. //! //! ### Use the `Set` variant of any of these `Map`s when: //! * You just want to remember which keys you've seen.