diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d6932c7ca3ce1..9f75f9ebb9adf 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -242,7 +242,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ConstVal { Float(f64), Int(i64), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4efa7bfac1813..22a4ddd2f687b 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -28,6 +28,7 @@ use middle::def; use middle::lang_items; use middle::ty::{self, Ty}; use middle::def_id::{DefId, DefIndex}; +use mir::repr::Mir; use session::Session; use session::search_paths::PathKind; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; @@ -100,6 +101,7 @@ pub enum InlinedItem { } /// A borrowed version of `hir::InlinedItem`. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum InlinedItemRef<'a> { Item(&'a hir::Item), TraitItem(DefId, &'a hir::TraitItem), @@ -216,6 +218,8 @@ pub trait CrateStore<'tcx> : Any { // misc. metadata fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) -> FoundAst<'tcx>; + fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Option>; // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; @@ -235,6 +239,7 @@ pub trait CrateStore<'tcx> : Any { item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, + mir_map: &NodeMap>, krate: &hir::Crate) -> Vec; fn metadata_encoding_version(&self) -> &[u8]; } @@ -383,6 +388,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // misc. metadata fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) -> FoundAst<'tcx> { unimplemented!() } + fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Option> { unimplemented!() } + // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec { vec![] } @@ -404,6 +412,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, + mir_map: &NodeMap>, krate: &hir::Crate) -> Vec { vec![] } fn metadata_encoding_version(&self) -> &[u8] { unimplemented!() } } diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index 425a324c7e084..66b2a9d3ad0bf 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -10,6 +10,7 @@ //! This module contains TypeVariants and its major components +use middle::cstore; use middle::def_id::DefId; use middle::region; use middle::subst::{self, Substs}; @@ -26,6 +27,8 @@ use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::special_idents; +use serialize::{Decodable, Decoder}; + use rustc_front::hir; use self::FnOutput::*; @@ -233,7 +236,7 @@ pub enum TypeVariants<'tcx> { /// closure C wind up influencing the decisions we ought to make for /// closure C (which would then require fixed point iteration to /// handle). Plus it fixes an ICE. :P -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function. /// These are separated out because trans wants to pass them around @@ -246,6 +249,23 @@ pub struct ClosureSubsts<'tcx> { pub upvar_tys: Vec> } +impl<'tcx> Decodable for &'tcx ClosureSubsts<'tcx> { + fn decode(s: &mut S) -> Result<&'tcx ClosureSubsts<'tcx>, S::Error> { + let closure_substs = try! { Decodable::decode(s) }; + let dummy_def_id: DefId = unsafe { mem::zeroed() }; + + cstore::tls::with_decoding_context(s, |dcx, _| { + // Intern the value + let ty = dcx.tcx().mk_closure_from_closure_substs(dummy_def_id, + Box::new(closure_substs)); + match ty.sty { + TyClosure(_, ref closure_substs) => Ok(&**closure_substs), + _ => unreachable!() + } + }) + } +} + #[derive(Clone, PartialEq, Eq, Hash)] pub struct TraitTy<'tcx> { pub principal: ty::PolyTraitRef<'tcx>, @@ -434,7 +454,7 @@ pub struct ClosureTy<'tcx> { pub sig: PolyFnSig<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum FnOutput<'tcx> { FnConverging(Ty<'tcx>), FnDiverging @@ -632,7 +652,7 @@ pub struct DebruijnIndex { /// /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -#[derive(Clone, PartialEq, Eq, Hash, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)] pub enum Region { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type @@ -701,7 +721,7 @@ pub struct RegionVid { pub index: u32 } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct SkolemizedRegionVid { pub index: u32 } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index d5d8da248e081..049063f73a5bf 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -13,6 +13,7 @@ use middle::def_id::DefId; use middle::subst::Substs; use middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty}; use rustc_back::slice; +use rustc_data_structures::tuple_slice::TupleSlice; use rustc_front::hir::InlineAsm; use syntax::ast::Name; use syntax::codemap::Span; @@ -20,6 +21,7 @@ use std::fmt::{Debug, Formatter, Error}; use std::u32; /// Lowered representation of a single function. +#[derive(RustcEncodable, RustcDecodable)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. @@ -70,13 +72,13 @@ impl<'tcx> Mir<'tcx> { /////////////////////////////////////////////////////////////////////////// // Mutability and borrow kinds -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum Mutability { Mut, Not, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -127,6 +129,7 @@ pub enum BorrowKind { // A "variable" is a binding declared by the user as part of the fn // decl, a let, etc. +#[derive(RustcEncodable, RustcDecodable)] pub struct VarDecl<'tcx> { pub mutability: Mutability, pub name: Name, @@ -135,6 +138,7 @@ pub struct VarDecl<'tcx> { // A "temp" is a temporary that we place on the stack. They are // anonymous, always mutable, and have only a type. +#[derive(RustcEncodable, RustcDecodable)] pub struct TempDecl<'tcx> { pub ty: Ty<'tcx>, } @@ -150,6 +154,7 @@ pub struct TempDecl<'tcx> { // // there is only one argument, of type `(i32, u32)`, but two bindings // (`x` and `y`). +#[derive(RustcEncodable, RustcDecodable)] pub struct ArgDecl<'tcx> { pub ty: Ty<'tcx>, } @@ -161,7 +166,7 @@ pub struct ArgDecl<'tcx> { /// list of the `Mir`. /// /// (We use a `u32` internally just to save memory.) -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct BasicBlock(u32); impl BasicBlock { @@ -185,12 +190,13 @@ impl Debug for BasicBlock { /////////////////////////////////////////////////////////////////////////// // BasicBlock and Terminator -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct BasicBlockData<'tcx> { pub statements: Vec>, pub terminator: Terminator<'tcx>, } +#[derive(RustcEncodable, RustcDecodable)] pub enum Terminator<'tcx> { /// block should have one successor in the graph; we jump there Goto { @@ -206,7 +212,7 @@ pub enum Terminator<'tcx> { /// jump to branch 0 if this lvalue evaluates to true If { cond: Operand<'tcx>, - targets: [BasicBlock; 2], + targets: (BasicBlock, BasicBlock), }, /// lvalue evaluates to some enum; jump depending on the branch @@ -254,7 +260,7 @@ pub enum Terminator<'tcx> { /// unwinding. Call { data: CallData<'tcx>, - targets: [BasicBlock; 2], + targets: (BasicBlock, BasicBlock), }, } @@ -264,12 +270,12 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref b } => slice::ref_slice(b), Panic { target: ref b } => slice::ref_slice(b), - If { cond: _, targets: ref b } => b, + If { cond: _, targets: ref b } => b.as_slice(), Switch { targets: ref b, .. } => b, SwitchInt { targets: ref b, .. } => b, Diverge => &[], Return => &[], - Call { data: _, targets: ref b } => b, + Call { data: _, targets: ref b } => b.as_slice(), } } @@ -278,17 +284,17 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref mut b } => slice::mut_ref_slice(b), Panic { target: ref mut b } => slice::mut_ref_slice(b), - If { cond: _, targets: ref mut b } => b, + If { cond: _, targets: ref mut b } => b.as_mut_slice(), Switch { targets: ref mut b, .. } => b, SwitchInt { targets: ref mut b, .. } => b, Diverge => &mut [], Return => &mut [], - Call { data: _, targets: ref mut b } => b, + Call { data: _, targets: ref mut b } => b.as_mut_slice(), } } } -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CallData<'tcx> { /// where the return value is written to pub destination: Lvalue<'tcx>, @@ -345,18 +351,19 @@ impl<'tcx> Debug for Terminator<'tcx> { /////////////////////////////////////////////////////////////////////////// // Statements +#[derive(RustcEncodable, RustcDecodable)] pub struct Statement<'tcx> { pub span: Span, pub kind: StatementKind<'tcx>, } -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub enum StatementKind<'tcx> { Assign(Lvalue<'tcx>, Rvalue<'tcx>), Drop(DropKind, Lvalue<'tcx>), } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum DropKind { Free, // free a partially constructed box, should go away eventually Deep @@ -377,7 +384,7 @@ impl<'tcx> Debug for Statement<'tcx> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lvalue<'tcx> { /// local variable declared by the user Var(u32), @@ -403,13 +410,13 @@ pub enum Lvalue<'tcx> { /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases /// `LvalueProjection` etc below. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub struct Projection<'tcx, B, V> { pub base: B, pub elem: ProjectionElem<'tcx, V>, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum ProjectionElem<'tcx, V> { Deref, Field(Field), @@ -447,7 +454,7 @@ pub type LvalueElem<'tcx> = ProjectionElem<'tcx,Operand<'tcx>>; /// Index into the list of fields found in a `VariantDef` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct Field(u32); impl Field { @@ -523,7 +530,7 @@ impl<'tcx> Debug for Lvalue<'tcx> { // lvalue). They are intentionally limited to prevent rvalues from // being nested in one another. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Operand<'tcx> { Consume(Lvalue<'tcx>), Constant(Constant<'tcx>), @@ -542,7 +549,7 @@ impl<'tcx> Debug for Operand<'tcx> { /////////////////////////////////////////////////////////////////////////// // Rvalues -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub enum Rvalue<'tcx> { // x (either a move or copy, depending on type of x) Use(Operand<'tcx>), @@ -583,10 +590,10 @@ pub enum Rvalue<'tcx> { from_end: usize, }, - InlineAsm(&'tcx InlineAsm), + InlineAsm(InlineAsm), } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CastKind { Misc, @@ -604,7 +611,7 @@ pub enum CastKind { Unsize, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum AggregateKind<'tcx> { Vec, Tuple, @@ -612,7 +619,7 @@ pub enum AggregateKind<'tcx> { Closure(DefId, &'tcx ClosureSubsts<'tcx>), } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum BinOp { /// The `+` operator (addition) Add, @@ -648,7 +655,7 @@ pub enum BinOp { Gt, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum UnOp { /// The `!` operator for logical inversion Not, @@ -684,14 +691,14 @@ impl<'tcx> Debug for Rvalue<'tcx> { // this does not necessarily mean that they are "==" in Rust -- in // particular one must be wary of `NaN`! -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub struct Constant<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub literal: Literal<'tcx>, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { Item { def_id: DefId, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ac4f54b4b4962..00d21d3c16e1f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -8,8 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::def_id::DefId; use middle::ty::Region; use mir::repr::*; +use rustc_data_structures::tuple_slice::TupleSlice; +use syntax::codemap::Span; pub trait Visitor<'tcx> { // Override these, and call `self.super_xxx` to revert back to the @@ -55,6 +58,18 @@ pub trait Visitor<'tcx> { self.super_constant(constant); } + fn visit_literal(&mut self, literal: &Literal<'tcx>) { + self.super_literal(literal); + } + + fn visit_def_id(&mut self, def_id: DefId) { + self.super_def_id(def_id); + } + + fn visit_span(&mut self, span: Span) { + self.super_span(span); + } + // The `super_xxx` methods comprise the default behavior and are // not meant to be overidden. @@ -73,6 +88,8 @@ pub trait Visitor<'tcx> { } fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) { + self.visit_span(statement.span); + match statement.kind { StatementKind::Assign(ref lvalue, ref rvalue) => { self.visit_assign(block, lvalue, rvalue); @@ -97,7 +114,7 @@ pub trait Visitor<'tcx> { Terminator::If { ref cond, ref targets } => { self.visit_operand(cond); - for &target in &targets[..] { + for &target in targets.as_slice() { self.visit_branch(block, target); } } @@ -126,7 +143,7 @@ pub trait Visitor<'tcx> { for arg in &data.args { self.visit_operand(arg); } - for &target in &targets[..] { + for &target in targets.as_slice() { self.visit_branch(block, target); } } @@ -217,7 +234,26 @@ pub trait Visitor<'tcx> { fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) { } - fn super_constant(&mut self, _constant: &Constant<'tcx>) { + fn super_constant(&mut self, constant: &Constant<'tcx>) { + self.visit_span(constant.span); + self.visit_literal(&constant.literal); + } + + fn super_literal(&mut self, literal: &Literal<'tcx>) { + match *literal { + Literal::Item { def_id, .. } => { + self.visit_def_id(def_id); + }, + Literal::Value { .. } => { + // Nothing to do + } + } + } + + fn super_def_id(&mut self, _def_id: DefId) { + } + + fn super_span(&mut self, _span: Span) { } } @@ -244,3 +280,277 @@ pub enum LvalueContext { // Consumed as part of an operand Consume, } + +pub trait MutVisitor<'tcx> { + // Override these, and call `self.super_xxx` to revert back to the + // default behavior. + + fn visit_mir(&mut self, mir: &mut Mir<'tcx>) { + self.super_mir(mir); + } + + fn visit_basic_block_data(&mut self, + block: BasicBlock, + data: &mut BasicBlockData<'tcx>) { + self.super_basic_block_data(block, data); + } + + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>) { + self.super_statement(block, statement); + } + + fn visit_assign(&mut self, + block: BasicBlock, + lvalue: &mut Lvalue<'tcx>, + rvalue: &mut Rvalue<'tcx>) { + self.super_assign(block, lvalue, rvalue); + } + + fn visit_terminator(&mut self, + block: BasicBlock, + terminator: &mut Terminator<'tcx>) { + self.super_terminator(block, terminator); + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) { + self.super_rvalue(rvalue); + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>) { + self.super_operand(operand); + } + + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext) { + self.super_lvalue(lvalue, context); + } + + fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) { + self.super_branch(source, target); + } + + fn visit_constant(&mut self, constant: &mut Constant<'tcx>) { + self.super_constant(constant); + } + + fn visit_literal(&mut self, literal: &mut Literal<'tcx>) { + self.super_literal(literal); + } + + fn visit_def_id(&mut self, def_id: &mut DefId) { + self.super_def_id(def_id); + } + + fn visit_span(&mut self, span: &mut Span) { + self.super_span(span); + } + + // The `super_xxx` methods comprise the default behavior and are + // not meant to be overidden. + + fn super_mir(&mut self, mir: &mut Mir<'tcx>) { + for block in mir.all_basic_blocks() { + let data = mir.basic_block_data_mut(block); + self.visit_basic_block_data(block, data); + } + } + + fn super_basic_block_data(&mut self, + block: BasicBlock, + data: &mut BasicBlockData<'tcx>) { + for statement in &mut data.statements { + self.visit_statement(block, statement); + } + self.visit_terminator(block, &mut data.terminator); + } + + fn super_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>) { + self.visit_span(&mut statement.span); + + match statement.kind { + StatementKind::Assign(ref mut lvalue, ref mut rvalue) => { + self.visit_assign(block, lvalue, rvalue); + } + StatementKind::Drop(_, ref mut lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Drop); + } + } + } + + fn super_assign(&mut self, + _block: BasicBlock, + lvalue: &mut Lvalue<'tcx>, + rvalue: &mut Rvalue<'tcx>) { + self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_rvalue(rvalue); + } + + fn super_terminator(&mut self, + block: BasicBlock, + terminator: &mut Terminator<'tcx>) { + match *terminator { + Terminator::Goto { target } | + Terminator::Panic { target } => { + self.visit_branch(block, target); + } + + Terminator::If { ref mut cond, ref mut targets } => { + self.visit_operand(cond); + for &target in targets.as_slice() { + self.visit_branch(block, target); + } + } + + Terminator::Switch { ref mut discr, adt_def: _, ref targets } => { + self.visit_lvalue(discr, LvalueContext::Inspect); + for &target in targets { + self.visit_branch(block, target); + } + } + + Terminator::SwitchInt { ref mut discr, switch_ty: _, values: _, ref targets } => { + self.visit_lvalue(discr, LvalueContext::Inspect); + for &target in targets { + self.visit_branch(block, target); + } + } + + Terminator::Diverge | + Terminator::Return => { + } + + Terminator::Call { ref mut data, ref mut targets } => { + self.visit_lvalue(&mut data.destination, LvalueContext::Store); + self.visit_operand(&mut data.func); + for arg in &mut data.args { + self.visit_operand(arg); + } + for &target in targets.as_slice() { + self.visit_branch(block, target); + } + } + } + } + + fn super_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) { + match *rvalue { + Rvalue::Use(ref mut operand) => { + self.visit_operand(operand); + } + + Rvalue::Repeat(ref mut value, ref mut len) => { + self.visit_operand(value); + self.visit_constant(len); + } + + Rvalue::Ref(r, bk, ref mut path) => { + self.visit_lvalue(path, LvalueContext::Borrow { + region: r, + kind: bk + }); + } + + Rvalue::Len(ref mut path) => { + self.visit_lvalue(path, LvalueContext::Inspect); + } + + Rvalue::Cast(_, ref mut operand, _) => { + self.visit_operand(operand); + } + + Rvalue::BinaryOp(_, ref mut lhs, ref mut rhs) => { + self.visit_operand(lhs); + self.visit_operand(rhs); + } + + Rvalue::UnaryOp(_, ref mut op) => { + self.visit_operand(op); + } + + Rvalue::Box(_) => { + } + + Rvalue::Aggregate(ref mut kind, ref mut operands) => { + match *kind { + AggregateKind::Closure(ref mut def_id, _) => { + self.visit_def_id(def_id); + } + _ => { /* nothing to do */ } + } + + for operand in &mut operands[..] { + self.visit_operand(operand); + } + } + + Rvalue::Slice { ref mut input, from_start, from_end } => { + self.visit_lvalue(input, LvalueContext::Slice { + from_start: from_start, + from_end: from_end, + }); + } + + Rvalue::InlineAsm(_) => { + } + } + } + + fn super_operand(&mut self, operand: &mut Operand<'tcx>) { + match *operand { + Operand::Consume(ref mut lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Consume); + } + Operand::Constant(ref mut constant) => { + self.visit_constant(constant); + } + } + } + + fn super_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + _context: LvalueContext) { + match *lvalue { + Lvalue::Var(_) | + Lvalue::Temp(_) | + Lvalue::Arg(_) | + Lvalue::ReturnPointer => { + } + Lvalue::Static(ref mut def_id) => { + self.visit_def_id(def_id); + } + Lvalue::Projection(ref mut proj) => { + self.visit_lvalue(&mut proj.base, LvalueContext::Projection); + } + } + } + + fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) { + } + + fn super_constant(&mut self, constant: &mut Constant<'tcx>) { + self.visit_span(&mut constant.span); + self.visit_literal(&mut constant.literal); + } + + fn super_literal(&mut self, literal: &mut Literal<'tcx>) { + match *literal { + Literal::Item { ref mut def_id, .. } => { + self.visit_def_id(def_id); + }, + Literal::Value { .. } => { + // Nothing to do + } + } + } + + fn super_def_id(&mut self, _def_id: &mut DefId) { + } + + fn super_span(&mut self, _span: &mut Span) { + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 39b3842791fa6..0ea7cfa3902fa 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -42,6 +42,7 @@ pub mod snapshot_vec; pub mod transitive_relation; pub mod unify; pub mod fnv; +pub mod tuple_slice; // See comments in src/librustc/lib.rs #[doc(hidden)] diff --git a/src/librustc_data_structures/tuple_slice.rs b/src/librustc_data_structures/tuple_slice.rs new file mode 100644 index 0000000000000..f157d82eda12b --- /dev/null +++ b/src/librustc_data_structures/tuple_slice.rs @@ -0,0 +1,60 @@ +// Copyright 2014 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. + +use std::slice; + +/// Allows to view uniform tuples as slices +pub trait TupleSlice { + fn as_slice(&self) -> &[T]; + fn as_mut_slice(&mut self) -> &mut [T]; +} + +macro_rules! impl_tuple_slice { + ($tuple_type:ty, $size:expr) => { + impl TupleSlice for $tuple_type { + fn as_slice(&self) -> &[T] { + unsafe { + let ptr = &self.0 as *const T; + slice::from_raw_parts(ptr, $size) + } + } + + fn as_mut_slice(&mut self) -> &mut [T] { + unsafe { + let ptr = &mut self.0 as *mut T; + slice::from_raw_parts_mut(ptr, $size) + } + } + } + } +} + +impl_tuple_slice!((T,T), 2); +impl_tuple_slice!((T,T,T), 3); +impl_tuple_slice!((T,T,T,T), 4); +impl_tuple_slice!((T,T,T,T,T), 5); +impl_tuple_slice!((T,T,T,T,T,T), 6); +impl_tuple_slice!((T,T,T,T,T,T,T), 7); +impl_tuple_slice!((T,T,T,T,T,T,T,T), 8); + +#[test] +fn test_sliced_tuples() { + let t2 = (100i32, 101i32); + assert_eq!(t2.as_slice(), &[100i32, 101i32]); + + let t3 = (102i32, 103i32, 104i32); + assert_eq!(t3.as_slice(), &[102i32, 103i32, 104i32]); + + let t4 = (105i32, 106i32, 107i32, 108i32); + assert_eq!(t4.as_slice(), &[105i32, 106i32, 107i32, 108i32]); + + let t5 = (109i32, 110i32, 111i32, 112i32, 113i32); + assert_eq!(t5.as_slice(), &[109i32, 110i32, 111i32, 112i32, 113i32]); +} diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index b6454a4c81a2f..5186c96913341 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -120,7 +120,8 @@ enum_from_u32! { tag_tree = 0x51, - // GAP 0x52 + tag_mir = 0x52, + tag_table = 0x53, // GAP 0x54, 0x55 tag_table_def = 0x56, diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index aae3a762c197a..ad00ef29e5f60 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -22,6 +22,7 @@ use middle::ty::{self, Ty}; use middle::def_id::{DefId, DefIndex}; use rustc::front::map as hir_map; +use rustc::mir::repr::Mir; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::RefCell; @@ -421,6 +422,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item) } + fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Option> { + let cdata = self.get_crate_data(def.krate); + decoder::maybe_get_item_mir(&*cdata, tcx, def.index) + } + fn crates(&self) -> Vec { let mut result = vec![]; @@ -473,6 +480,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, + mir_map: &NodeMap>, krate: &hir::Crate) -> Vec { let encode_inlined_item: encoder::EncodeInlinedItem = @@ -486,7 +494,8 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { link_meta: link_meta, cstore: self, encode_inlined_item: encode_inlined_item, - reachable: reachable + reachable: reachable, + mir_map: mir_map, }; encoder::encode_metadata(encode_params, krate) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c139ec4f62a5e..d1917b29b9f12 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -18,6 +18,7 @@ use cstore::{self, crate_metadata}; use common::*; use encoder::def_to_u64; use index; +use tls_context; use tydecode::TyDecoder; use rustc::back::svh::Svh; @@ -26,7 +27,7 @@ use rustc::util::nodemap::FnvHashMap; use rustc_front::hir; use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference}; -use middle::cstore::{DefLike, DlDef, DlField, DlImpl}; +use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use middle::def; use middle::def_id::{DefId, DefIndex}; use middle::lang_items; @@ -34,6 +35,9 @@ use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty::{self, RegionEscape, Ty}; +use rustc::mir; +use rustc::mir::visit::MutVisitor; + use std::cell::{Cell, RefCell}; use std::io::prelude::*; use std::io; @@ -48,7 +52,7 @@ use syntax::parse::token::{IdentInterner, special_idents}; use syntax::parse::token; use syntax::ast; use syntax::abi; -use syntax::codemap; +use syntax::codemap::{self, Span}; use syntax::print::pprust; use syntax::ptr::P; @@ -783,6 +787,56 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex, } } +pub fn maybe_get_item_mir<'tcx>(cdata: Cmd, + tcx: &ty::ctxt<'tcx>, + id: DefIndex) + -> Option> { + let item_doc = cdata.lookup_item(id); + + return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| { + let dcx = tls_context::DecodingContext { + crate_metadata: cdata, + tcx: tcx, + }; + let mut decoder = reader::Decoder::new(mir_doc); + + let mut mir = tls::enter_decoding_context(&dcx, &mut decoder, |_, decoder| { + Decodable::decode(decoder).unwrap() + }); + + let mut def_id_and_span_translator = MirDefIdAndSpanTranslator { + crate_metadata: cdata, + codemap: tcx.sess.codemap(), + last_filemap_index_hint: Cell::new(0), + }; + + def_id_and_span_translator.visit_mir(&mut mir); + + mir + }); + + struct MirDefIdAndSpanTranslator<'cdata, 'codemap> { + crate_metadata: Cmd<'cdata>, + codemap: &'codemap codemap::CodeMap, + last_filemap_index_hint: Cell + } + + impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v> + for MirDefIdAndSpanTranslator<'cdata, 'codemap> + { + fn visit_def_id(&mut self, def_id: &mut DefId) { + *def_id = translate_def_id(self.crate_metadata, *def_id); + } + + fn visit_span(&mut self, span: &mut Span) { + *span = translate_span(self.crate_metadata, + self.codemap, + &self.last_filemap_index_hint, + *span); + } + } +} + fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { fn get_mutability(ch: u8) -> hir::Mutability { match ch as char { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 448a64c93c1c4..a627eeb688075 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -30,6 +30,7 @@ use middle::ty::{self, Ty}; use rustc::back::svh::Svh; use rustc::front::map::{LinkedPath, PathElem, PathElems}; use rustc::front::map as ast_map; +use rustc::mir::repr::Mir; use rustc::session::config; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; @@ -64,6 +65,7 @@ pub struct EncodeParams<'a, 'tcx: 'a> { pub cstore: &'a cstore::CStore, pub encode_inlined_item: EncodeInlinedItem<'a>, pub reachable: &'a NodeSet, + pub mir_map: &'a NodeMap>, } pub struct EncodeContext<'a, 'tcx: 'a> { @@ -76,6 +78,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { pub encode_inlined_item: RefCell>, pub type_abbrevs: tyencode::abbrev_map<'tcx>, pub reachable: &'a NodeSet, + pub mir_map: &'a NodeMap>, } impl<'a, 'tcx> EncodeContext<'a,'tcx> { @@ -840,7 +843,24 @@ fn encode_inlined_item(ecx: &EncodeContext, ii: InlinedItemRef) { let mut eii = ecx.encode_inlined_item.borrow_mut(); let eii: &mut EncodeInlinedItem = &mut *eii; - eii(ecx, rbml_w, ii) + eii(ecx, rbml_w, ii); + + encode_mir(ecx, rbml_w, ii); +} + +fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, ii: InlinedItemRef) { + let id = match ii { + InlinedItemRef::Item(item) => item.id, + InlinedItemRef::TraitItem(_, trait_item) => trait_item.id, + InlinedItemRef::ImplItem(_, impl_item) => impl_item.id, + InlinedItemRef::Foreign(foreign_item) => foreign_item.id + }; + + if let Some(mir) = ecx.mir_map.get(&id) { + rbml_w.start_tag(tag_mir as usize); + Encodable::encode(mir, rbml_w).unwrap(); + rbml_w.end_tag(); + } } const FN_FAMILY: char = 'f'; @@ -1884,6 +1904,7 @@ pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec { encode_inlined_item, link_meta, reachable, + mir_map, .. } = parms; let ecx = EncodeContext { @@ -1896,6 +1917,7 @@ pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec { encode_inlined_item: RefCell::new(encode_inlined_item), type_abbrevs: RefCell::new(FnvHashMap()), reachable: reachable, + mir_map: mir_map, }; let mut wr = Cursor::new(Vec::new()); diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 697799efd143b..1c96addcea0d9 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -69,7 +69,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.cfg.terminate(block, Terminator::If { cond: Operand::Consume(lt), - targets: [success, failure], + targets: (success, failure), }); this.panic(failure); success.and(slice.index(idx)) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 7f69b9a521f11..2f57dd22454cb 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -40,7 +40,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.in_scope(extent, block, |this| this.as_rvalue(block, value)) } ExprKind::InlineAsm { asm } => { - block.and(Rvalue::InlineAsm(asm)) + block.and(Rvalue::InlineAsm(asm.clone())) } ExprKind::Repeat { value, count } => { let value_operand = unpack!(block = this.as_operand(block, value)); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ac3e87e6b629a..802c55ce7647a 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -53,7 +53,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let mut else_block = this.cfg.start_new_block(); this.cfg.terminate(block, Terminator::If { cond: operand, - targets: [then_block, else_block] + targets: (then_block, else_block) }); unpack!(then_block = this.into(destination, then_block, then_expr)); @@ -84,15 +84,15 @@ impl<'a,'tcx> Builder<'a,'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 => (else_block, false_block), + LogicalOp::Or => (true_block, else_block), }; this.cfg.terminate(block, Terminator::If { cond: lhs, targets: blocks }); let rhs = unpack!(else_block = this.as_operand(else_block, rhs)); this.cfg.terminate(else_block, Terminator::If { cond: rhs, - targets: [true_block, false_block] + targets: (true_block, false_block) }); this.cfg.push_assign_constant( @@ -149,7 +149,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.cfg.terminate(loop_block_end, Terminator::If { cond: cond, - targets: [body_block, exit_block] + targets: (body_block, exit_block) }); } else { body_block = loop_block; @@ -225,7 +225,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { func: fun, args: args, }, - targets: [success, panic], + targets: (success, panic), }); success.unit() } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 0248f2fc49adb..f8385d5817018 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -555,7 +555,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); self.cfg.terminate(block, Terminator::If { cond: cond, - targets: [arm_block, otherwise]}); + targets: (arm_block, otherwise)}); Some(otherwise) } else { self.cfg.terminate(block, Terminator::Goto { target: arm_block }); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 968514cd05c13..7b329fc4d52c3 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -232,7 +232,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.cfg.start_new_block()]; self.cfg.terminate(block, Terminator::If { cond: Operand::Consume(result), - targets: [target_blocks[0], target_blocks[1]] + targets: (target_blocks[0], target_blocks[1]) }); target_blocks @@ -252,7 +252,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty); let func = self.item_ref_operand(span, item_ref); - let call_blocks = [self.cfg.start_new_block(), self.diverge_cleanup()]; + let call_blocks = (self.cfg.start_new_block(), self.diverge_cleanup()); self.cfg.terminate(block, Terminator::Call { data: CallData { @@ -264,10 +264,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { }); // check the result - self.cfg.terminate(call_blocks[0], + self.cfg.terminate(call_blocks.0, Terminator::If { cond: Operand::Consume(eq_result), - targets: [target_blocks[0], target_blocks[1]], + targets: (target_blocks[0], target_blocks[1]), }); target_blocks diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 558276a13a8b8..d0c0afc80a657 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -96,9 +96,9 @@ impl SimplifyCfg { mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator); mir.basic_block_data_mut(bb).terminator = match terminator { - Terminator::If { ref targets, .. } if targets[0] == targets[1] => { + Terminator::If { ref targets, .. } if targets.0 == targets.1 => { changed = true; - Terminator::Goto { target: targets[0] } + Terminator::Goto { target: targets.0 } } Terminator::If { ref targets, cond: Operand::Constant(Constant { literal: Literal::Value { @@ -106,8 +106,11 @@ impl SimplifyCfg { }, .. }) } => { changed = true; - let target_idx = if cond { 0 } else { 1 }; - Terminator::Goto { target: targets[target_idx] } + if cond { + Terminator::Goto { target: targets.0 } + } else { + Terminator::Goto { target: targets.1 } + } } Terminator::SwitchInt { ref targets, .. } if targets.len() == 1 => { Terminator::Goto { target: targets[0] } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index dde6e3935b25d..838a5435d4fee 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2760,7 +2760,11 @@ fn register_method(ccx: &CrateContext, } } -pub fn write_metadata(cx: &SharedCrateContext, krate: &hir::Crate, reachable: &NodeSet) -> Vec { +pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, + krate: &hir::Crate, + reachable: &NodeSet, + mir_map: &MirMap<'tcx>) + -> Vec { use flate; let any_library = cx.sess() @@ -2773,9 +2777,13 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &hir::Crate, reachable: &N } let cstore = &cx.tcx().sess.cstore; - let metadata = cstore.encode_metadata( - cx.tcx(), cx.export_map(), cx.item_symbols(), cx.link_meta(), reachable, - krate); + let metadata = cstore.encode_metadata(cx.tcx(), + cx.export_map(), + cx.item_symbols(), + cx.link_meta(), + reachable, + mir_map, + krate); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); @@ -3045,7 +3053,7 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>, let reachable_symbol_ids = filter_reachable_ids(&shared_ccx); // Translate the metadata. - let metadata = write_metadata(&shared_ccx, krate, &reachable_symbol_ids); + let metadata = write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map); if shared_ccx.sess().trans_stats() { let stats = shared_ccx.stats(); diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 3ce08fb2f60ef..b58b51f5a2b23 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -39,7 +39,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { unimplemented!() } - mir::Terminator::If { ref cond, targets: [true_bb, false_bb] } => { + mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => { let cond = self.trans_operand(bcx, cond); let lltrue = self.llblock(true_bb); let llfalse = self.llblock(false_bb); diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 17e4ec8e8274c..529e65dace04c 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -120,7 +120,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx } - mir::Rvalue::InlineAsm(inline_asm) => { + mir::Rvalue::InlineAsm(ref inline_asm) => { asm::trans_inline_asm(bcx, inline_asm) }