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 diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4e67a14345b9e..5858e077173ff 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -149,6 +149,7 @@ struct Build { python: Option, full_bootstrap: Option, extended: Option, + verbose: Option, } /// TOML representation of various global install decisions. @@ -294,6 +295,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); 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 # ============================================================================= diff --git a/src/doc/reference.md b/src/doc/reference.md index f9013490418f3..8aefabe61fdf6 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1291,15 +1291,18 @@ 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 -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 the `static` lifetime, fixed-size arrays, tuples, enum variants, and structs. -``` +```rust const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; @@ -1317,6 +1320,8 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` + + ### Static items A *static item* is similar to a *constant*, except that it represents a precise @@ -1351,7 +1356,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; @@ -1375,6 +1380,53 @@ 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] 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)] +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, +}; +``` + +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 @@ -2072,7 +2124,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 @@ -2489,9 +2543,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 diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index f583f601726ed..11919db479c1a 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; @@ -48,4 +49,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 cbb7b2710f506..d8212807eb277 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -453,36 +453,30 @@ 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>, - 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 { /// discriminant value being tested - discr: Lvalue<'tcx>, + discr: Operand<'tcx>, /// type of value being tested switch_ty: Ty<'tcx>, /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - values: Vec, - - /// 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. + values: Cow<'tcx, [ConstInt]>, + + /// 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, }, @@ -546,12 +540,21 @@ 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 { 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(), Return => (&[]).into_cow(), @@ -580,8 +583,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(), Return => Vec::new(), @@ -659,8 +660,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"), Resume => write!(fmt, "resume"), @@ -710,18 +709,11 @@ 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() - .map(|variant| variant.name.to_string().into()) - .collect() - } SwitchInt { ref values, .. } => { 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())) @@ -997,6 +989,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 +1109,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..7b0863b4c42bc 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -18,6 +18,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use hir; +use ty::util::IntTypeExt; #[derive(Copy, Clone, Debug)] pub enum LvalueTy<'tcx> { @@ -135,15 +136,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 +153,37 @@ 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) => { + let ty = lval.ty(mir, tcx).to_ty(tcx); + if let ty::TyAdt(adt_def, _) = ty.sty { + Some(adt_def.discr_ty.to_ty(tcx)) + } else { + // Undefined behaviour, bug for now; may want to return something for + // the `discriminant` intrinsic later. + bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty); + } + } + Rvalue::Box(t) => { Some(tcx.mk_box(t)) } - &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 +207,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..be3c43db7badd 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; @@ -224,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) { @@ -363,31 +368,14 @@ 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 } => { - 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, + ref 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); + for value in &values[..] { + self.visit_const_int(value, source_location); } for &target in targets { self.visit_branch(block, target); @@ -506,6 +494,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); } @@ -712,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/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..b21e6492dbce5 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,11 +1206,7 @@ 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 = v.disr_val as i128 as i64; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } @@ -1271,7 +1266,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 4d9514b1473c7..122624f751602 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; @@ -96,7 +95,7 @@ mod flags; mod structural_impls; mod sty; -pub type Disr = ConstInt; +pub type Disr = u128; // Data types @@ -1325,6 +1324,12 @@ pub struct FieldDef { /// table. pub struct AdtDef { pub did: DefId, + /// Type of the discriminant + /// + /// Note, that this is the type specified in `repr()` or a default type of some sort, and might + /// not match the actual type that layout algorithm decides to use when translating this type + /// into LLVM. That being said, layout algorithm may not use a type larger than specified here. + pub discr_ty: attr::IntType, pub variants: Vec, destructor: Cell>, flags: Cell @@ -1360,6 +1365,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 +1388,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..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, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; use std::cell::RefCell; @@ -37,84 +36,20 @@ use syntax_pos::Span; 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 to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; + 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: '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), } } - 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 disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) - -> Option { - if let Some(val) = val { - self.assert_ty_matches(val); - (val + ConstInt::Infer(1)).ok() - } else { - Some(self.initial_discriminant(tcx)) - } + fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { + 0 } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index f11cf90834dd9..8b246105f6169 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -454,11 +454,6 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> self.propagate_bits_into_entry_set_for(in_out, changed, target); self.propagate_bits_into_entry_set_for(in_out, changed, 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 { 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 d2f744bde2d63..5899c9f31d14d 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; @@ -619,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 - { - let subpath = super::move_path_children_matching( - self.move_data(), c.path, |proj| match proj { - &Projection { - elem: ProjectionElem::Downcast(_, idx), .. - } => idx == variant_index, - _ => false - }); - - if let Some(variant_path) = subpath { - let base_lv = c.lvalue.clone().elem( - ProjectionElem::Downcast(adt, variant_index) - ); - let fields = self.move_paths_for_fields( - &base_lv, - variant_path, - &adt.variants[variant_index], - substs); - self.drop_ladder(c, fields) - } else { - // variant not found - drop the entire enum - if let None = *drop_block { - *drop_block = Some(self.complete_drop(c, true)); - } - return drop_block.unwrap(); - } - } - fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, 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( @@ -672,12 +636,43 @@ 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()); + let mut otherwise = None; + 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 subpath = super::move_path_children_matching( + self.move_data(), c.path, |proj| match proj { + &Projection { + elem: ProjectionElem::Downcast(_, idx), .. + } => idx == variant_index, + _ => false + }); + if let Some(variant_path) = subpath { + let base_lv = c.lvalue.clone().elem( + ProjectionElem::Downcast(adt, variant_index) + ); + let fields = self.move_paths_for_fields( + &base_lv, + variant_path, + &adt.variants[variant_index], + substs); + values.push(discr); + blocks.push(self.drop_ladder(c, fields)); + } else { + // variant not found - drop the entire enum + if let None = otherwise { + otherwise = Some(self.complete_drop(c, true)); + } + } + } + if let Some(block) = otherwise { + blocks.push(block); + } else { + values.pop(); + } // If there are multiple variants, then if something // is present within the enum the discriminant, tracked // by the rest path, must be initialized. @@ -685,14 +680,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // Additionally, we do not want to switch on the // 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: From::from(values), + targets: blocks, + } + }), + is_cleanup: c.is_cleanup, + }); self.drop_flag_test_block(c, switch_block) } } @@ -813,10 +821,8 @@ 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 term = TerminatorKind::if_(self.tcx, Operand::Consume(flag), on_set, on_unset); + self.new_block(c, is_cleanup, term) } } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 7cf6ab2999c05..0c7e922c48ab4 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(..) => { @@ -463,10 +464,8 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { self.gather_move(loc, &Lvalue::Local(RETURN_POINTER)); } - TerminatorKind::If { .. } | 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_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_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 3d4af259ec9f7..35841c2cbdf01 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -69,10 +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::If { - cond: operand, - targets: (then_block, else_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 { @@ -114,14 +112,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { LogicalOp::And => (else_block, false_block), LogicalOp::Or => (true_block, else_block), }; - this.cfg.terminate(block, source_info, - TerminatorKind::If { cond: lhs, 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::If { - cond: rhs, - targets: (true_block, false_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, @@ -179,11 +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::If { - cond: cond, - targets: (body_block, exit_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 5c3d93ffda9c1..a28bc5d6ce36d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -673,8 +673,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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)}); + 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 a35b2925ae271..01c0433112bf3 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -20,8 +20,9 @@ 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::ty::util::IntTypeExt; use rustc::mir::*; use rustc::hir::RangeEnd; use syntax_pos::Span; @@ -182,74 +183,82 @@ 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(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); + let discr_ty = adt_def.discr_ty.to_ty(tcx); + let discr = self.temp(discr_ty); + self.cfg.push_assign(block, source_info, &discr, + Rvalue::Discriminant(lvalue.clone())); + assert_eq!(values.len() + 1, targets.len()); + self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { + discr: Operand::Consume(discr), + switch_ty: discr_ty, + values: From::from(values), + targets: targets }); target_blocks } 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::If { - cond: Operand::Consume(lvalue.clone()), - targets: (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: lvalue.clone(), - switch_ty: switch_ty, - values: options.clone(), - targets: targets - }) - } + 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()); + 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) + }; + (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 + 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(); + (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, term); - targets + self.cfg.terminate(block, source_info, terminator); + ret } TestKind::Eq { ref value, mut ty } => { @@ -314,11 +323,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::If { - cond: Operand::Consume(eq_result), - targets: (block, fail), - }); - + 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); @@ -360,14 +368,12 @@ 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()]; - self.cfg.terminate(block, source_info, TerminatorKind::If { - cond: Operand::Consume(result), - targets: (target_blocks[0], target_blocks[1]) - }); - - target_blocks + let (false_bb, true_bb) = (self.cfg.start_new_block(), + self.cfg.start_new_block()); + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result), + true_bb, false_bb)); + vec![true_bb, false_bb] } } } @@ -389,11 +395,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::If { - cond: Operand::Consume(result), - targets: (target_block, fail_block) - }); - + self.cfg.terminate(block, source_info, + TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result), + 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/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 6ef5720b330c9..55a26f4b37fe2 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -28,8 +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 9c1107344f241..922521726c626 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -394,8 +394,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { return Qualif::empty(); } - TerminatorKind::If {..} | - TerminatorKind::Switch {..} | TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | @@ -739,6 +737,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } + Rvalue::Discriminant(..) => { + // FIXME discriminant + self.add(Qualif::NOT_CONST); + if self.mode != Mode::Fn { + bug!("implement discriminant const qualify"); + } + } + Rvalue::Box(_) => { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index d5fc90289e2cc..e93a412dc744f 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -209,8 +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..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 } + 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 { - TerminatorKind::Goto { target: targets.1 } + continue } - } - + }, TerminatorKind::Assert { target, cond: Operand::Constant(Constant { literal: Literal::Value { value: ConstVal::Bool(cond) }, .. }), expected, .. } if cond == expected => { TerminatorKind::Goto { target: target } - } - + }, _ => continue }; } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 529fe564af02b..8ede7aaab5f68 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); @@ -446,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); @@ -603,11 +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::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 { 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 cec1c20519bd6..517a472056334 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -148,8 +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", TerminatorKind::Return => "TerminatorKind::Return", @@ -186,6 +184,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/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 7578cc74dbf34..9ae83991962a5 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_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2a1ab10d74e16..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); @@ -204,8 +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..6b3081f610060 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -11,17 +11,16 @@ 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}; -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 +28,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,59 +134,28 @@ 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()); - 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)) + mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { + let discr = self.trans_operand(&bcx, discr); + if switch_ty == bcx.tcx().types.bool { + let lltrue = llblock(self, targets[0]); + let llfalse = llblock(self, targets[1]); + if let [ConstInt::Infer(0)] = values[..] { + bcx.cond_br(discr.immediate(), llfalse, lltrue); + } else { + bcx.cond_br(discr.immediate(), lltrue, llfalse); } - // 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) + } 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) } } } - mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - 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 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) - } - } - mir::TerminatorKind::Return => { let ret = self.fn_ty.ret; if ret.is_ignore() || ret.is_indirect() { 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/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 81b241b485175..6874a0245b0b9 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -429,6 +429,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }) } + mir::Rvalue::Discriminant(ref lvalue) => { + let discr_lvalue = self.trans_lvalue(&bcx, lvalue); + let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx()); + let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap(); + let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty); + let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, + Some(discr_type), true); + (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 +670,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, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1981e7c3a3d12..60f4870a7aa12 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,64 @@ 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 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(_)) | + (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 } } +} fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item, @@ -1089,13 +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 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.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, @@ -1107,12 +1111,10 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, None }.unwrap_or(wrapped_disr); prev_disr = Some(disr); - let did = tcx.hir.local_def_id(v.node.data.id()); - convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) + convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data) }).collect(); - - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants); + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants); tcx.adt_defs.borrow_mut().insert(did, adt); adt } 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/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| { 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. 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 /// /// ``` diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs index ac47f6082e3e3..aa100da60132f 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: 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_]+]] +// CHECK: [[OTHERWISE]]: +// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]] match e { E::A => (), E::B => (), 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/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 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 {} 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)] 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