From bbe1d28496c194afce54f5a2c3a83140bf4bb3a7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 19 Nov 2015 16:37:34 +0100 Subject: Move the core MIR datastructures to librustc. This is done mostly so that we can refer to MIR types in csearch and other metadata related area. --- src/librustc/lib.rs | 5 + src/librustc/mir/repr.rs | 703 ++++++++++++++++++++++++++++ src/librustc/mir/tcx.rs | 190 ++++++++ src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/expr/as_constant.rs | 2 +- src/librustc_mir/build/expr/as_lvalue.rs | 4 +- src/librustc_mir/build/expr/as_operand.rs | 4 +- src/librustc_mir/build/expr/as_rvalue.rs | 4 +- src/librustc_mir/build/expr/as_temp.rs | 4 +- src/librustc_mir/build/expr/into.rs | 4 +- src/librustc_mir/build/into.rs | 4 +- src/librustc_mir/build/matches/mod.rs | 4 +- src/librustc_mir/build/matches/simplify.rs | 4 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/matches/util.rs | 4 +- src/librustc_mir/build/misc.rs | 2 +- src/librustc_mir/build/mod.rs | 10 +- src/librustc_mir/build/scope.rs | 4 +- src/librustc_mir/build/stmt.rs | 4 +- src/librustc_mir/graphviz/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 2 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/lib.rs | 2 - src/librustc_mir/mir_map.rs | 2 +- src/librustc_mir/repr.rs | 703 ---------------------------- src/librustc_mir/tcx/mod.rs | 190 -------- src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/simplify_cfg.rs | 2 +- src/librustc_mir/transform/util.rs | 2 +- src/librustc_mir/visit.rs | 2 +- src/librustc_trans/trans/common.rs | 4 +- src/librustc_trans/trans/mir/analyze.rs | 2 +- src/librustc_trans/trans/mir/block.rs | 2 +- src/librustc_trans/trans/mir/constant.rs | 2 +- src/librustc_trans/trans/mir/lvalue.rs | 4 +- src/librustc_trans/trans/mir/mod.rs | 4 +- src/librustc_trans/trans/mir/operand.rs | 2 +- src/librustc_trans/trans/mir/rvalue.rs | 2 +- src/librustc_trans/trans/mir/statement.rs | 2 +- 43 files changed, 956 insertions(+), 947 deletions(-) create mode 100644 src/librustc/mir/repr.rs create mode 100644 src/librustc/mir/tcx.rs delete mode 100644 src/librustc_mir/repr.rs delete mode 100644 src/librustc_mir/tcx/mod.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 72319227ccb..d75a4495a0e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -136,6 +136,11 @@ pub mod middle { pub mod weak_lang_items; } +pub mod mir { + pub mod repr; + pub mod tcx; +} + pub mod session; pub mod lint; diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs new file mode 100644 index 00000000000..d5d8da248e0 --- /dev/null +++ b/src/librustc/mir/repr.rs @@ -0,0 +1,703 @@ +// 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 middle::const_eval::ConstVal; +use middle::def_id::DefId; +use middle::subst::Substs; +use middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty}; +use rustc_back::slice; +use rustc_front::hir::InlineAsm; +use syntax::ast::Name; +use syntax::codemap::Span; +use std::fmt::{Debug, Formatter, Error}; +use std::u32; + +/// Lowered representation of a single function. +pub struct Mir<'tcx> { + /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` + /// that indexes into this vector. + pub basic_blocks: Vec>, + + /// Return type of the function. + pub return_ty: FnOutput<'tcx>, + + /// Variables: these are stack slots corresponding to user variables. They may be + /// assigned many times. + pub var_decls: Vec>, + + /// Args: these are stack slots corresponding to the input arguments. + pub arg_decls: Vec>, + + /// Temp declarations: stack slots that for temporaries created by + /// the compiler. These are assigned once, but they are not SSA + /// values in that it is possible to borrow them and mutate them + /// through the resulting reference. + pub temp_decls: Vec>, +} + +/// where execution begins +pub const START_BLOCK: BasicBlock = BasicBlock(0); + +/// where execution ends, on normal return +pub const END_BLOCK: BasicBlock = BasicBlock(1); + +/// where execution ends, on panic +pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2); + +impl<'tcx> Mir<'tcx> { + pub fn all_basic_blocks(&self) -> Vec { + (0..self.basic_blocks.len()) + .map(|i| BasicBlock::new(i)) + .collect() + } + + pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> { + &self.basic_blocks[bb.index()] + } + + pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> { + &mut self.basic_blocks[bb.index()] + } +} + +/////////////////////////////////////////////////////////////////////////// +// Mutability and borrow kinds + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Mutability { + Mut, + Not, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// Data must be immutable but not aliasable. This kind of borrow + /// cannot currently be expressed by the user and is used only in + /// implicit closure bindings. It is needed when you the closure + /// is borrowing or mutating a mutable referent, e.g.: + /// + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// + /// If we were to try to translate this closure into a more explicit + /// form, we'd encounter an error with the code as written: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// This is then illegal because you cannot mutate a `&mut` found + /// in an aliasable location. To solve, you'd have to translate with + /// an `&mut` borrow: + /// + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// + /// Now the assignment to `**env.x` is legal, but creating a + /// mutable pointer to `x` is not because `x` is not mutable. We + /// could fix this by declaring `x` as `let mut x`. This is ok in + /// user code, if awkward, but extra weird for closures, since the + /// borrow is hidden. + /// + /// So we introduce a "unique imm" borrow -- the referent is + /// immutable, but not aliasable. This solves the problem. For + /// simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + Unique, + + /// Data is mutable and not aliasable. + Mut, +} + +/////////////////////////////////////////////////////////////////////////// +// Variables and temps + +// A "variable" is a binding declared by the user as part of the fn +// decl, a let, etc. +pub struct VarDecl<'tcx> { + pub mutability: Mutability, + pub name: Name, + pub ty: Ty<'tcx>, +} + +// A "temp" is a temporary that we place on the stack. They are +// anonymous, always mutable, and have only a type. +pub struct TempDecl<'tcx> { + pub ty: Ty<'tcx>, +} + +// A "arg" is one of the function's formal arguments. These are +// anonymous and distinct from the bindings that the user declares. +// +// For example, in this function: +// +// ``` +// fn foo((x, y): (i32, u32)) { ... } +// ``` +// +// there is only one argument, of type `(i32, u32)`, but two bindings +// (`x` and `y`). +pub struct ArgDecl<'tcx> { + pub ty: Ty<'tcx>, +} + +/////////////////////////////////////////////////////////////////////////// +// BasicBlock + +/// The index of a particular basic block. The index is into the `basic_blocks` +/// list of the `Mir`. +/// +/// (We use a `u32` internally just to save memory.) +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct BasicBlock(u32); + +impl BasicBlock { + pub fn new(index: usize) -> BasicBlock { + assert!(index < (u32::MAX as usize)); + BasicBlock(index as u32) + } + + /// Extract the index. + pub fn index(self) -> usize { + self.0 as usize + } +} + +impl Debug for BasicBlock { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + write!(fmt, "BB({})", self.0) + } +} + +/////////////////////////////////////////////////////////////////////////// +// BasicBlock and Terminator + +#[derive(Debug)] +pub struct BasicBlockData<'tcx> { + pub statements: Vec>, + pub terminator: Terminator<'tcx>, +} + +pub enum Terminator<'tcx> { + /// block should have one successor in the graph; we jump there + Goto { + target: BasicBlock, + }, + + /// block should initiate unwinding; should be one successor + /// that does cleanup and branches to DIVERGE_BLOCK + Panic { + target: BasicBlock, + }, + + /// jump to branch 0 if this lvalue evaluates to true + If { + cond: Operand<'tcx>, + targets: [BasicBlock; 2], + }, + + /// lvalue evaluates to some enum; jump depending on the branch + Switch { + discr: Lvalue<'tcx>, + adt_def: AdtDef<'tcx>, + 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>, + + /// 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. + targets: Vec, + }, + + /// Indicates that the last statement in the block panics, aborts, + /// etc. No successors. This terminator appears on exactly one + /// basic block which we create in advance. However, during + /// construction, we use this value as a sentinel for "terminator + /// not yet assigned", and assert at the end that only the + /// well-known diverging block actually diverges. + Diverge, + + /// Indicates a normal return. The ReturnPointer lvalue should + /// have been filled in by now. This should only occur in the + /// `END_BLOCK`. + Return, + + /// block ends with a call; it should have two successors. The + /// first successor indicates normal return. The second indicates + /// unwinding. + Call { + data: CallData<'tcx>, + targets: [BasicBlock; 2], + }, +} + +impl<'tcx> Terminator<'tcx> { + pub fn successors(&self) -> &[BasicBlock] { + use self::Terminator::*; + match *self { + Goto { target: ref b } => slice::ref_slice(b), + Panic { target: ref b } => slice::ref_slice(b), + If { cond: _, targets: ref b } => b, + Switch { targets: ref b, .. } => b, + SwitchInt { targets: ref b, .. } => b, + Diverge => &[], + Return => &[], + Call { data: _, targets: ref b } => b, + } + } + + pub fn successors_mut(&mut self) -> &mut [BasicBlock] { + use self::Terminator::*; + 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, + Switch { targets: ref mut b, .. } => b, + SwitchInt { targets: ref mut b, .. } => b, + Diverge => &mut [], + Return => &mut [], + Call { data: _, targets: ref mut b } => b, + } + } +} + +#[derive(Debug)] +pub struct CallData<'tcx> { + /// where the return value is written to + pub destination: Lvalue<'tcx>, + + /// the fn being called + pub func: Operand<'tcx>, + + /// the arguments + pub args: Vec>, +} + +impl<'tcx> BasicBlockData<'tcx> { + pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> { + BasicBlockData { + statements: vec![], + terminator: terminator, + } + } +} + +impl<'tcx> Debug for Terminator<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::Terminator::*; + match *self { + Goto { target } => + write!(fmt, "goto -> {:?}", target), + Panic { target } => + write!(fmt, "panic -> {:?}", target), + If { cond: ref lv, ref targets } => + write!(fmt, "if({:?}) -> {:?}", lv, targets), + Switch { discr: ref lv, adt_def: _, ref targets } => + write!(fmt, "switch({:?}) -> {:?}", lv, targets), + SwitchInt { discr: ref lv, switch_ty: _, ref values, ref targets } => + write!(fmt, "switchInt({:?}, {:?}) -> {:?}", lv, values, targets), + Diverge => + write!(fmt, "diverge"), + Return => + write!(fmt, "return"), + Call { data: ref c, targets } => { + try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func)); + for (index, arg) in c.args.iter().enumerate() { + if index > 0 { + try!(write!(fmt, ", ")); + } + try!(write!(fmt, "{:?}", arg)); + } + write!(fmt, ") -> {:?}", targets) + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////// +// Statements + +pub struct Statement<'tcx> { + pub span: Span, + pub kind: StatementKind<'tcx>, +} + +#[derive(Debug)] +pub enum StatementKind<'tcx> { + Assign(Lvalue<'tcx>, Rvalue<'tcx>), + Drop(DropKind, Lvalue<'tcx>), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum DropKind { + Free, // free a partially constructed box, should go away eventually + Deep +} + +impl<'tcx> Debug for Statement<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::StatementKind::*; + match self.kind { + Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv), + Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv), + Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv), + } + } +} +/////////////////////////////////////////////////////////////////////////// +// Lvalues + +/// A path to a value; something that can be evaluated without +/// changing or disturbing program state. +#[derive(Clone, PartialEq)] +pub enum Lvalue<'tcx> { + /// local variable declared by the user + Var(u32), + + /// temporary introduced during lowering into MIR + Temp(u32), + + /// formal parameter of the function; note that these are NOT the + /// bindings that the user declares, which are vars + Arg(u32), + + /// static or static mut variable + Static(DefId), + + /// the return pointer of the fn + ReturnPointer, + + /// projection out of an lvalue (access a field, deref a pointer, etc) + Projection(Box>), +} + +/// The `Projection` data structure defines things of the form `B.x` +/// 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)] +pub struct Projection<'tcx, B, V> { + pub base: B, + pub elem: ProjectionElem<'tcx, V>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ProjectionElem<'tcx, V> { + Deref, + Field(Field), + Index(V), + + // These indices are generated by slice patterns. Easiest to explain + // by example: + // + // ``` + // [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, + // [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, + // [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, + // [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, + // ``` + ConstantIndex { + offset: u32, // index or -index (in Python terms), depending on from_end + min_length: u32, // thing being indexed must be at least this long + from_end: bool, // counting backwards from end? + }, + + // "Downcast" to a variant of an ADT. Currently, we only introduce + // this for ADTs with more than one variant. It may be better to + // just introduce it always, or always for enums. + Downcast(AdtDef<'tcx>, usize), +} + +/// Alias for projections as they appear in lvalues, where the base is an lvalue +/// and the index is an operand. +pub type LvalueProjection<'tcx> = + Projection<'tcx,Lvalue<'tcx>,Operand<'tcx>>; + +/// Alias for projections as they appear in lvalues, where the base is an lvalue +/// and the index is an operand. +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)] +pub struct Field(u32); + +impl Field { + pub fn new(value: usize) -> Field { + assert!(value < (u32::MAX) as usize); + Field(value as u32) + } + + pub fn index(self) -> usize { + self.0 as usize + } +} + +impl<'tcx> Lvalue<'tcx> { + pub fn field(self, f: Field) -> Lvalue<'tcx> { + self.elem(ProjectionElem::Field(f)) + } + + pub fn deref(self) -> Lvalue<'tcx> { + self.elem(ProjectionElem::Deref) + } + + pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> { + self.elem(ProjectionElem::Index(index)) + } + + pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> { + Lvalue::Projection(Box::new(LvalueProjection { + base: self, + elem: elem, + })) + } +} + +impl<'tcx> Debug for Lvalue<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::Lvalue::*; + + match *self { + Var(id) => + write!(fmt,"Var({:?})", id), + Arg(id) => + write!(fmt,"Arg({:?})", id), + Temp(id) => + write!(fmt,"Temp({:?})", id), + Static(id) => + write!(fmt,"Static({:?})", id), + ReturnPointer => + write!(fmt,"ReturnPointer"), + Projection(ref data) => + match data.elem { + ProjectionElem::Downcast(_, variant_index) => + write!(fmt,"({:?} as {:?})", data.base, variant_index), + ProjectionElem::Deref => + write!(fmt,"(*{:?})", data.base), + ProjectionElem::Field(field) => + write!(fmt,"{:?}.{:?}", data.base, field.index()), + ProjectionElem::Index(ref index) => + write!(fmt,"{:?}[{:?}]", data.base, index), + ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => + write!(fmt,"{:?}[{:?} of {:?}]", data.base, offset, min_length), + ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => + write!(fmt,"{:?}[-{:?} of {:?}]", data.base, offset, min_length), + }, + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Operands +// +// These are values that can appear inside an rvalue (or an index +// lvalue). They are intentionally limited to prevent rvalues from +// being nested in one another. + +#[derive(Clone, PartialEq)] +pub enum Operand<'tcx> { + Consume(Lvalue<'tcx>), + Constant(Constant<'tcx>), +} + +impl<'tcx> Debug for Operand<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::Operand::*; + match *self { + Constant(ref a) => write!(fmt, "{:?}", a), + Consume(ref lv) => write!(fmt, "{:?}", lv), + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Rvalues + +#[derive(Clone)] +pub enum Rvalue<'tcx> { + // x (either a move or copy, depending on type of x) + Use(Operand<'tcx>), + + // [x; 32] + Repeat(Operand<'tcx>, Constant<'tcx>), + + // &x or &mut x + Ref(Region, BorrowKind, Lvalue<'tcx>), + + // length of a [X] or [X;n] value + Len(Lvalue<'tcx>), + + Cast(CastKind, Operand<'tcx>, Ty<'tcx>), + + BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), + + UnaryOp(UnOp, Operand<'tcx>), + + // Creates an *uninitialized* Box + Box(Ty<'tcx>), + + // Create an aggregate value, like a tuple or struct. This is + // only needed because we want to distinguish `dest = Foo { x: + // ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case + // that `Foo` has a destructor. These rvalues can be optimized + // away after type-checking and before lowering. + Aggregate(AggregateKind<'tcx>, Vec>), + + // Generates a slice of the form `&input[from_start..L-from_end]` + // where `L` is the length of the slice. This is only created by + // slice pattern matching, so e.g. a pattern of the form `[x, y, + // .., z]` might create a slice with `from_start=2` and + // `from_end=1`. + Slice { + input: Lvalue<'tcx>, + from_start: usize, + from_end: usize, + }, + + InlineAsm(&'tcx InlineAsm), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CastKind { + Misc, + + /// Convert unique, zero-sized type for a fn to fn() + ReifyFnPointer, + + /// Convert safe fn() to unsafe fn() + UnsafeFnPointer, + + /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. + /// trans must figure out the details once full monomorphization + /// is known. For example, this could be used to cast from a + /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` + /// (presuming `T: Trait`). + Unsize, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum AggregateKind<'tcx> { + Vec, + Tuple, + Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>), + Closure(DefId, &'tcx ClosureSubsts<'tcx>), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum BinOp { + /// The `+` operator (addition) + Add, + /// The `-` operator (subtraction) + Sub, + /// The `*` operator (multiplication) + Mul, + /// The `/` operator (division) + Div, + /// The `%` operator (modulus) + Rem, + /// The `^` operator (bitwise xor) + BitXor, + /// The `&` operator (bitwise and) + BitAnd, + /// The `|` operator (bitwise or) + BitOr, + /// The `<<` operator (shift left) + Shl, + /// The `>>` operator (shift right) + Shr, + /// The `==` operator (equality) + Eq, + /// The `<` operator (less than) + Lt, + /// The `<=` operator (less than or equal to) + Le, + /// The `!=` operator (not equal to) + Ne, + /// The `>=` operator (greater than or equal to) + Ge, + /// The `>` operator (greater than) + Gt, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum UnOp { + /// The `!` operator for logical inversion + Not, + /// The `-` operator for negation + Neg, +} + +impl<'tcx> Debug for Rvalue<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::Rvalue::*; + + match *self { + Use(ref lvalue) => write!(fmt, "{:?}", lvalue), + Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), + Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b), + Len(ref a) => write!(fmt, "LEN({:?})", a), + Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?}", lv, ty, kind), + BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?},{:?})", op, a, b), + UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), + Box(ref t) => write!(fmt, "Box {:?}", t), + Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs), + InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm), + Slice { ref input, from_start, from_end } => + write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end), + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Constants +// +// Two constants are equal if they are the same constant. Note that +// this does not necessarily mean that they are "==" in Rust -- in +// particular one must be wary of `NaN`! + +#[derive(Clone, Debug, PartialEq)] +pub struct Constant<'tcx> { + pub span: Span, + pub ty: Ty<'tcx>, + pub literal: Literal<'tcx>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Literal<'tcx> { + Item { + def_id: DefId, + substs: &'tcx Substs<'tcx>, + }, + Value { + value: ConstVal, + }, +} diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs new file mode 100644 index 00000000000..45cc0b8b413 --- /dev/null +++ b/src/librustc/mir/tcx.rs @@ -0,0 +1,190 @@ +// Copyright 2015 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. + +/*! + * Methods for the various MIR types. These are intended for use after + * building is complete. + */ + +use mir::repr::*; +use middle::subst::Substs; +use middle::ty::{self, AdtDef, Ty}; +use rustc_front::hir; + +#[derive(Copy, Clone, Debug)] +pub enum LvalueTy<'tcx> { + /// Normal type. + Ty { ty: Ty<'tcx> }, + + /// Downcast to a particular variant of an enum. + Downcast { adt_def: AdtDef<'tcx>, + substs: &'tcx Substs<'tcx>, + variant_index: usize }, +} + +impl<'tcx> LvalueTy<'tcx> { + pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> { + LvalueTy::Ty { ty: ty } + } + + pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + LvalueTy::Ty { ty } => + ty, + LvalueTy::Downcast { adt_def, substs, variant_index: _ } => + tcx.mk_enum(adt_def, substs), + } + } + + pub fn projection_ty(self, + tcx: &ty::ctxt<'tcx>, + elem: &LvalueElem<'tcx>) + -> LvalueTy<'tcx> + { + match *elem { + ProjectionElem::Deref => + LvalueTy::Ty { + ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference) + .unwrap() + .ty + }, + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => + LvalueTy::Ty { + ty: self.to_ty(tcx).builtin_index().unwrap() + }, + ProjectionElem::Downcast(adt_def1, index) => + match self.to_ty(tcx).sty { + ty::TyEnum(adt_def, substs) => { + assert!(index < adt_def.variants.len()); + assert_eq!(adt_def, adt_def1); + LvalueTy::Downcast { adt_def: adt_def, + substs: substs, + variant_index: index } + } + _ => { + tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self)) + } + }, + ProjectionElem::Field(field) => { + let field_ty = match self { + LvalueTy::Ty { ty } => match ty.sty { + ty::TyStruct(adt_def, substs) => + adt_def.struct_variant().fields[field.index()].ty(tcx, substs), + ty::TyTuple(ref tys) => + tys[field.index()], + ty::TyClosure(_, ref closure_substs) => + closure_substs.upvar_tys[field.index()], + _ => + tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)), + }, + LvalueTy::Downcast { adt_def, substs, variant_index } => + adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs), + }; + LvalueTy::Ty { ty: field_ty } + } + } + } +} + +impl<'tcx> Mir<'tcx> { + pub fn operand_ty(&self, + tcx: &ty::ctxt<'tcx>, + operand: &Operand<'tcx>) + -> Ty<'tcx> + { + match *operand { + Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx), + Operand::Constant(ref c) => c.ty, + } + } + + pub fn binop_ty(&self, + tcx: &ty::ctxt<'tcx>, + op: BinOp, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>) + -> Ty<'tcx> + { + // FIXME: handle SIMD correctly + match op { + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | + BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => { + // these should be integers or floats of the same size. + assert_eq!(lhs_ty, rhs_ty); + lhs_ty + } + BinOp::Shl | BinOp::Shr => { + lhs_ty // lhs_ty can be != rhs_ty + } + BinOp::Eq | BinOp::Lt | BinOp::Le | + BinOp::Ne | BinOp::Ge | BinOp::Gt => { + tcx.types.bool + } + } + } + + pub fn lvalue_ty(&self, + tcx: &ty::ctxt<'tcx>, + lvalue: &Lvalue<'tcx>) + -> LvalueTy<'tcx> + { + match *lvalue { + Lvalue::Var(index) => + LvalueTy::Ty { ty: self.var_decls[index as usize].ty }, + Lvalue::Temp(index) => + LvalueTy::Ty { ty: self.temp_decls[index as usize].ty }, + Lvalue::Arg(index) => + LvalueTy::Ty { ty: self.arg_decls[index as usize].ty }, + Lvalue::Static(def_id) => + LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, + Lvalue::ReturnPointer => + LvalueTy::Ty { ty: self.return_ty.unwrap() }, + Lvalue::Projection(ref proj) => + self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem) + } + } +} + +impl BorrowKind { + pub fn to_mutbl_lossy(self) -> hir::Mutability { + match self { + BorrowKind::Mut => hir::MutMutable, + BorrowKind::Shared => hir::MutImmutable, + + // We have no type corresponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + BorrowKind::Unique => hir::MutMutable, + } + } +} + +impl BinOp { + pub fn to_hir_binop(self) -> hir::BinOp_ { + match self { + BinOp::Add => hir::BinOp_::BiAdd, + BinOp::Sub => hir::BinOp_::BiSub, + BinOp::Mul => hir::BinOp_::BiMul, + BinOp::Div => hir::BinOp_::BiDiv, + BinOp::Rem => hir::BinOp_::BiRem, + BinOp::BitXor => hir::BinOp_::BiBitXor, + BinOp::BitAnd => hir::BinOp_::BiBitAnd, + BinOp::BitOr => hir::BinOp_::BiBitOr, + BinOp::Shl => hir::BinOp_::BiShl, + BinOp::Shr => hir::BinOp_::BiShr, + BinOp::Eq => hir::BinOp_::BiEq, + BinOp::Ne => hir::BinOp_::BiNe, + BinOp::Lt => hir::BinOp_::BiLt, + BinOp::Gt => hir::BinOp_::BiGt, + BinOp::Le => hir::BinOp_::BiLe, + BinOp::Ge => hir::BinOp_::BiGe + } + } +} diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 21a77bbd232..5f7f87cb862 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -10,7 +10,7 @@ use build::{BlockAnd, Builder}; use hair::*; -use repr::*; +use rustc::mir::repr::*; use rustc_front::hir; impl<'a,'tcx> Builder<'a,'tcx> { diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index e44e3936885..d28724c30aa 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -14,7 +14,7 @@ //! Routines for manipulating the control-flow graph. use build::CFG; -use repr::*; +use rustc::mir::repr::*; use syntax::codemap::Span; impl<'tcx> CFG<'tcx> { diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index b362f981764..6f186b8ada4 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -12,7 +12,7 @@ use build::Builder; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index d93304f034d..697799efd14 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -10,10 +10,10 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding an lvalue that we can move from etc. diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index 6b2c487d0f5..7738ebca26b 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -10,10 +10,10 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr` into a value that can be used as an operand. diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 3f3bceef1eb..7f69b9a521f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -12,10 +12,10 @@ use rustc_data_structures::fnv::FnvHashMap; -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding an rvalue. diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index f0bbc6fb67e..53f8090ad0f 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -10,10 +10,10 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr` into a fresh temporary. This is used when building diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 7d79e90b3f1..ac3e87e6b62 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -10,12 +10,12 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use build::scope::LoopScope; use hair::*; -use repr::*; use rustc::middle::region::CodeExtent; +use rustc::mir::repr::*; use syntax::codemap::Span; impl<'a,'tcx> Builder<'a,'tcx> { diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs index c6f1b777d66..66d6c49ef12 100644 --- a/src/librustc_mir/build/into.rs +++ b/src/librustc_mir/build/into.rs @@ -14,9 +14,9 @@ //! wrapped up as expressions (e.g. blocks). To make this ergonomic, we use this //! latter `EvalInto` trait. -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; -use repr::*; +use rustc::mir::repr::*; pub trait EvalInto<'tcx> { fn eval_into<'a>(self, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index cc6155844bc..0248f2fc49a 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -13,12 +13,12 @@ //! includes the high-level algorithm, the submodules contain the //! details. -use build::{BlockAnd, Builder}; -use repr::*; +use build::{BlockAnd, BlockAndExtension, Builder}; use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval::ConstVal; use rustc::middle::region::CodeExtent; use rustc::middle::ty::{AdtDef, Ty}; +use rustc::mir::repr::*; use hair::*; use syntax::ast::{Name, NodeId}; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b9637addccf..2c8e1c1ccf6 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -22,10 +22,10 @@ //! sort of test: for example, testing which variant an enum is, or //! testing a value against a constant. -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::matches::{Binding, MatchPair, Candidate}; use hair::*; -use repr::*; +use rustc::mir::repr::*; use std::mem; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index dffd83f1c41..968514cd05c 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -18,10 +18,10 @@ use build::Builder; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; -use repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval::ConstVal; use rustc::middle::ty::{self, Ty}; +use rustc::mir::repr::*; use syntax::codemap::Span; impl<'a,'tcx> Builder<'a,'tcx> { diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 18dde5537da..dbb00a13cd3 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use build::matches::MatchPair; use hair::*; -use repr::*; +use rustc::mir::repr::*; use std::u32; impl<'a,'tcx> Builder<'a,'tcx> { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 41274f3f373..bdcb183c0ac 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -13,8 +13,8 @@ use build::Builder; use hair::*; -use repr::*; use rustc::middle::ty::Ty; +use rustc::mir::repr::*; use std::u32; use syntax::codemap::Span; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index f67c2920ba3..45368b5a68d 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -11,9 +11,10 @@ use hair::cx::Cx; use rustc::middle::region::CodeExtent; use rustc::middle::ty::{FnOutput, Ty}; +use rustc::mir::repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir; -use repr::*; + use syntax::ast; use syntax::codemap::Span; @@ -41,7 +42,12 @@ struct CFG<'tcx> { #[must_use] // if you don't use one of these results, you're leaving a dangling edge struct BlockAnd(BasicBlock, T); -impl BasicBlock { +trait BlockAndExtension { + fn and(self, v: T) -> BlockAnd; + fn unit(self) -> BlockAnd<()>; +} + +impl BlockAndExtension for BasicBlock { fn and(self, v: T) -> BlockAnd { BlockAnd(self, v) } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 1f3b6ad7bce..4d136d265e5 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -86,10 +86,10 @@ should go to. */ -use build::{BlockAnd, Builder, CFG}; -use repr::*; +use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use rustc::middle::region::CodeExtent; use rustc::middle::ty::Ty; +use rustc::mir::repr::*; use syntax::codemap::Span; pub struct Scope<'tcx> { diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs index ac6b2a3c531..c70b22893ae 100644 --- a/src/librustc_mir/build/stmt.rs +++ b/src/librustc_mir/build/stmt.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{BlockAnd, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; -use repr::*; +use rustc::mir::repr::*; impl<'a,'tcx> Builder<'a,'tcx> { pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec>) -> BlockAnd<()> { diff --git a/src/librustc_mir/graphviz/mod.rs b/src/librustc_mir/graphviz/mod.rs index 9da05a27e89..f8cec83dc31 100644 --- a/src/librustc_mir/graphviz/mod.rs +++ b/src/librustc_mir/graphviz/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use dot; -use repr::*; +use rustc::mir::repr::*; use std::borrow::IntoCow; #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 3380b3a6c14..24091d7dc37 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -9,7 +9,6 @@ // except according to those terms. use hair::*; -use repr::*; use rustc_data_structures::fnv::FnvHashMap; use hair::cx::Cx; use hair::cx::block; @@ -19,6 +18,7 @@ use rustc::middle::def; use rustc::middle::region::CodeExtent; use rustc::middle::pat_util; use rustc::middle::ty::{self, VariantDef, Ty}; +use rustc::mir::repr::*; use rustc_front::hir; use rustc_front::util as hir_util; use syntax::ext::mtwt; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index cb04df91042..8c19e620e46 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,7 @@ */ use hair::*; -use repr::*; +use rustc::mir::repr::*; use rustc::middle::const_eval::{self, ConstVal}; use rustc::middle::def_id::DefId; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 3d5cb831975..bea7950c33a 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -10,13 +10,13 @@ use hair::*; use hair::cx::Cx; -use repr::*; use rustc_data_structures::fnv::FnvHashMap; use rustc::middle::const_eval; use rustc::middle::def; use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; use rustc::middle::subst::Substs; use rustc::middle::ty::{self, Ty}; +use rustc::mir::repr::*; use rustc_front::hir; use syntax::ast; use syntax::ext::mtwt; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index d2d7faac627..9a774ff3f57 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,7 +14,7 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp}; +use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp}; use rustc::middle::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::middle::subst::Substs; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index c391a01960f..a3110df9ae4 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -32,9 +32,7 @@ extern crate syntax; pub mod build; pub mod mir_map; mod hair; -pub mod repr; mod graphviz; pub mod transform; -pub mod tcx; pub mod visit; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 34ef7c3487f..39a315f3c41 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -23,7 +23,7 @@ extern crate rustc_front; use build; use dot; use transform::*; -use repr::Mir; +use rustc::mir::repr::Mir; use hair::cx::Cx; use std::fs::File; diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs deleted file mode 100644 index dad8961a788..00000000000 --- a/src/librustc_mir/repr.rs +++ /dev/null @@ -1,703 +0,0 @@ -// 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 rustc::middle::const_eval::ConstVal; -use rustc::middle::def_id::DefId; -use rustc::middle::subst::Substs; -use rustc::middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty}; -use rustc_back::slice; -use rustc_front::hir::InlineAsm; -use syntax::ast::Name; -use syntax::codemap::Span; -use std::fmt::{Debug, Formatter, Error}; -use std::u32; - -/// Lowered representation of a single function. -pub struct Mir<'tcx> { - /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` - /// that indexes into this vector. - pub basic_blocks: Vec>, - - /// Return type of the function. - pub return_ty: FnOutput<'tcx>, - - /// Variables: these are stack slots corresponding to user variables. They may be - /// assigned many times. - pub var_decls: Vec>, - - /// Args: these are stack slots corresponding to the input arguments. - pub arg_decls: Vec>, - - /// Temp declarations: stack slots that for temporaries created by - /// the compiler. These are assigned once, but they are not SSA - /// values in that it is possible to borrow them and mutate them - /// through the resulting reference. - pub temp_decls: Vec>, -} - -/// where execution begins -pub const START_BLOCK: BasicBlock = BasicBlock(0); - -/// where execution ends, on normal return -pub const END_BLOCK: BasicBlock = BasicBlock(1); - -/// where execution ends, on panic -pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2); - -impl<'tcx> Mir<'tcx> { - pub fn all_basic_blocks(&self) -> Vec { - (0..self.basic_blocks.len()) - .map(|i| BasicBlock::new(i)) - .collect() - } - - pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> { - &self.basic_blocks[bb.index()] - } - - pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks[bb.index()] - } -} - -/////////////////////////////////////////////////////////////////////////// -// Mutability and borrow kinds - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Mutability { - Mut, - Not, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - Shared, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when you the closure - /// is borrowing or mutating a mutable referent, e.g.: - /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; - /// - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// This is then illegal because you cannot mutate a `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - Unique, - - /// Data is mutable and not aliasable. - Mut, -} - -/////////////////////////////////////////////////////////////////////////// -// Variables and temps - -// A "variable" is a binding declared by the user as part of the fn -// decl, a let, etc. -pub struct VarDecl<'tcx> { - pub mutability: Mutability, - pub name: Name, - pub ty: Ty<'tcx>, -} - -// A "temp" is a temporary that we place on the stack. They are -// anonymous, always mutable, and have only a type. -pub struct TempDecl<'tcx> { - pub ty: Ty<'tcx>, -} - -// A "arg" is one of the function's formal arguments. These are -// anonymous and distinct from the bindings that the user declares. -// -// For example, in this function: -// -// ``` -// fn foo((x, y): (i32, u32)) { ... } -// ``` -// -// there is only one argument, of type `(i32, u32)`, but two bindings -// (`x` and `y`). -pub struct ArgDecl<'tcx> { - pub ty: Ty<'tcx>, -} - -/////////////////////////////////////////////////////////////////////////// -// BasicBlock - -/// The index of a particular basic block. The index is into the `basic_blocks` -/// list of the `Mir`. -/// -/// (We use a `u32` internally just to save memory.) -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct BasicBlock(u32); - -impl BasicBlock { - pub fn new(index: usize) -> BasicBlock { - assert!(index < (u32::MAX as usize)); - BasicBlock(index as u32) - } - - /// Extract the index. - pub fn index(self) -> usize { - self.0 as usize - } -} - -impl Debug for BasicBlock { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - write!(fmt, "BB({})", self.0) - } -} - -/////////////////////////////////////////////////////////////////////////// -// BasicBlock and Terminator - -#[derive(Debug)] -pub struct BasicBlockData<'tcx> { - pub statements: Vec>, - pub terminator: Terminator<'tcx>, -} - -pub enum Terminator<'tcx> { - /// block should have one successor in the graph; we jump there - Goto { - target: BasicBlock, - }, - - /// block should initiate unwinding; should be one successor - /// that does cleanup and branches to DIVERGE_BLOCK - Panic { - target: BasicBlock, - }, - - /// jump to branch 0 if this lvalue evaluates to true - If { - cond: Operand<'tcx>, - targets: [BasicBlock; 2], - }, - - /// lvalue evaluates to some enum; jump depending on the branch - Switch { - discr: Lvalue<'tcx>, - adt_def: AdtDef<'tcx>, - 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>, - - /// 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. - targets: Vec, - }, - - /// Indicates that the last statement in the block panics, aborts, - /// etc. No successors. This terminator appears on exactly one - /// basic block which we create in advance. However, during - /// construction, we use this value as a sentinel for "terminator - /// not yet assigned", and assert at the end that only the - /// well-known diverging block actually diverges. - Diverge, - - /// Indicates a normal return. The ReturnPointer lvalue should - /// have been filled in by now. This should only occur in the - /// `END_BLOCK`. - Return, - - /// block ends with a call; it should have two successors. The - /// first successor indicates normal return. The second indicates - /// unwinding. - Call { - data: CallData<'tcx>, - targets: [BasicBlock; 2], - }, -} - -impl<'tcx> Terminator<'tcx> { - pub fn successors(&self) -> &[BasicBlock] { - use self::Terminator::*; - match *self { - Goto { target: ref b } => slice::ref_slice(b), - Panic { target: ref b } => slice::ref_slice(b), - If { cond: _, targets: ref b } => b, - Switch { targets: ref b, .. } => b, - SwitchInt { targets: ref b, .. } => b, - Diverge => &[], - Return => &[], - Call { data: _, targets: ref b } => b, - } - } - - pub fn successors_mut(&mut self) -> &mut [BasicBlock] { - use self::Terminator::*; - 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, - Switch { targets: ref mut b, .. } => b, - SwitchInt { targets: ref mut b, .. } => b, - Diverge => &mut [], - Return => &mut [], - Call { data: _, targets: ref mut b } => b, - } - } -} - -#[derive(Debug)] -pub struct CallData<'tcx> { - /// where the return value is written to - pub destination: Lvalue<'tcx>, - - /// the fn being called - pub func: Operand<'tcx>, - - /// the arguments - pub args: Vec>, -} - -impl<'tcx> BasicBlockData<'tcx> { - pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> { - BasicBlockData { - statements: vec![], - terminator: terminator, - } - } -} - -impl<'tcx> Debug for Terminator<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - use self::Terminator::*; - match *self { - Goto { target } => - write!(fmt, "goto -> {:?}", target), - Panic { target } => - write!(fmt, "panic -> {:?}", target), - If { cond: ref lv, ref targets } => - write!(fmt, "if({:?}) -> {:?}", lv, targets), - Switch { discr: ref lv, adt_def: _, ref targets } => - write!(fmt, "switch({:?}) -> {:?}", lv, targets), - SwitchInt { discr: ref lv, switch_ty: _, ref values, ref targets } => - write!(fmt, "switchInt({:?}, {:?}) -> {:?}", lv, values, targets), - Diverge => - write!(fmt, "diverge"), - Return => - write!(fmt, "return"), - Call { data: ref c, targets } => { - try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func)); - for (index, arg) in c.args.iter().enumerate() { - if index > 0 { - try!(write!(fmt, ", ")); - } - try!(write!(fmt, "{:?}", arg)); - } - write!(fmt, ") -> {:?}", targets) - } - } - } -} - - -/////////////////////////////////////////////////////////////////////////// -// Statements - -pub struct Statement<'tcx> { - pub span: Span, - pub kind: StatementKind<'tcx>, -} - -#[derive(Debug)] -pub enum StatementKind<'tcx> { - Assign(Lvalue<'tcx>, Rvalue<'tcx>), - Drop(DropKind, Lvalue<'tcx>), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum DropKind { - Free, // free a partially constructed box, should go away eventually - Deep -} - -impl<'tcx> Debug for Statement<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - use self::StatementKind::*; - match self.kind { - Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv), - Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv), - Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv), - } - } -} -/////////////////////////////////////////////////////////////////////////// -// Lvalues - -/// A path to a value; something that can be evaluated without -/// changing or disturbing program state. -#[derive(Clone, PartialEq)] -pub enum Lvalue<'tcx> { - /// local variable declared by the user - Var(u32), - - /// temporary introduced during lowering into MIR - Temp(u32), - - /// formal parameter of the function; note that these are NOT the - /// bindings that the user declares, which are vars - Arg(u32), - - /// static or static mut variable - Static(DefId), - - /// the return pointer of the fn - ReturnPointer, - - /// projection out of an lvalue (access a field, deref a pointer, etc) - Projection(Box>), -} - -/// The `Projection` data structure defines things of the form `B.x` -/// 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)] -pub struct Projection<'tcx, B, V> { - pub base: B, - pub elem: ProjectionElem<'tcx, V>, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum ProjectionElem<'tcx, V> { - Deref, - Field(Field), - Index(V), - - // These indices are generated by slice patterns. Easiest to explain - // by example: - // - // ``` - // [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, - // [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, - // [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, - // [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, - // ``` - ConstantIndex { - offset: u32, // index or -index (in Python terms), depending on from_end - min_length: u32, // thing being indexed must be at least this long - from_end: bool, // counting backwards from end? - }, - - // "Downcast" to a variant of an ADT. Currently, we only introduce - // this for ADTs with more than one variant. It may be better to - // just introduce it always, or always for enums. - Downcast(AdtDef<'tcx>, usize), -} - -/// Alias for projections as they appear in lvalues, where the base is an lvalue -/// and the index is an operand. -pub type LvalueProjection<'tcx> = - Projection<'tcx,Lvalue<'tcx>,Operand<'tcx>>; - -/// Alias for projections as they appear in lvalues, where the base is an lvalue -/// and the index is an operand. -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)] -pub struct Field(u32); - -impl Field { - pub fn new(value: usize) -> Field { - assert!(value < (u32::MAX) as usize); - Field(value as u32) - } - - pub fn index(self) -> usize { - self.0 as usize - } -} - -impl<'tcx> Lvalue<'tcx> { - pub fn field(self, f: Field) -> Lvalue<'tcx> { - self.elem(ProjectionElem::Field(f)) - } - - pub fn deref(self) -> Lvalue<'tcx> { - self.elem(ProjectionElem::Deref) - } - - pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> { - self.elem(ProjectionElem::Index(index)) - } - - pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> { - Lvalue::Projection(Box::new(LvalueProjection { - base: self, - elem: elem, - })) - } -} - -impl<'tcx> Debug for Lvalue<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - use self::Lvalue::*; - - match *self { - Var(id) => - write!(fmt,"Var({:?})", id), - Arg(id) => - write!(fmt,"Arg({:?})", id), - Temp(id) => - write!(fmt,"Temp({:?})", id), - Static(id) => - write!(fmt,"Static({:?})", id), - ReturnPointer => - write!(fmt,"ReturnPointer"), - Projection(ref data) => - match data.elem { - ProjectionElem::Downcast(_, variant_index) => - write!(fmt,"({:?} as {:?})", data.base, variant_index), - ProjectionElem::Deref => - write!(fmt,"(*{:?})", data.base), - ProjectionElem::Field(field) => - write!(fmt,"{:?}.{:?}", data.base, field.index()), - ProjectionElem::Index(ref index) => - write!(fmt,"{:?}[{:?}]", data.base, index), - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => - write!(fmt,"{:?}[{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => - write!(fmt,"{:?}[-{:?} of {:?}]", data.base, offset, min_length), - }, - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Operands -// -// These are values that can appear inside an rvalue (or an index -// lvalue). They are intentionally limited to prevent rvalues from -// being nested in one another. - -#[derive(Clone, PartialEq)] -pub enum Operand<'tcx> { - Consume(Lvalue<'tcx>), - Constant(Constant<'tcx>), -} - -impl<'tcx> Debug for Operand<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - use self::Operand::*; - match *self { - Constant(ref a) => write!(fmt, "{:?}", a), - Consume(ref lv) => write!(fmt, "{:?}", lv), - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Rvalues - -#[derive(Clone)] -pub enum Rvalue<'tcx> { - // x (either a move or copy, depending on type of x) - Use(Operand<'tcx>), - - // [x; 32] - Repeat(Operand<'tcx>, Constant<'tcx>), - - // &x or &mut x - Ref(Region, BorrowKind, Lvalue<'tcx>), - - // length of a [X] or [X;n] value - Len(Lvalue<'tcx>), - - Cast(CastKind, Operand<'tcx>, Ty<'tcx>), - - BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), - - UnaryOp(UnOp, Operand<'tcx>), - - // Creates an *uninitialized* Box - Box(Ty<'tcx>), - - // Create an aggregate value, like a tuple or struct. This is - // only needed because we want to distinguish `dest = Foo { x: - // ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case - // that `Foo` has a destructor. These rvalues can be optimized - // away after type-checking and before lowering. - Aggregate(AggregateKind<'tcx>, Vec>), - - // Generates a slice of the form `&input[from_start..L-from_end]` - // where `L` is the length of the slice. This is only created by - // slice pattern matching, so e.g. a pattern of the form `[x, y, - // .., z]` might create a slice with `from_start=2` and - // `from_end=1`. - Slice { - input: Lvalue<'tcx>, - from_start: usize, - from_end: usize, - }, - - InlineAsm(&'tcx InlineAsm), -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CastKind { - Misc, - - /// Convert unique, zero-sized type for a fn to fn() - ReifyFnPointer, - - /// Convert safe fn() to unsafe fn() - UnsafeFnPointer, - - /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. - /// trans must figure out the details once full monomorphization - /// is known. For example, this could be used to cast from a - /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` - /// (presuming `T: Trait`). - Unsize, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum AggregateKind<'tcx> { - Vec, - Tuple, - Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>), - Closure(DefId, &'tcx ClosureSubsts<'tcx>), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum BinOp { - /// The `+` operator (addition) - Add, - /// The `-` operator (subtraction) - Sub, - /// The `*` operator (multiplication) - Mul, - /// The `/` operator (division) - Div, - /// The `%` operator (modulus) - Rem, - /// The `^` operator (bitwise xor) - BitXor, - /// The `&` operator (bitwise and) - BitAnd, - /// The `|` operator (bitwise or) - BitOr, - /// The `<<` operator (shift left) - Shl, - /// The `>>` operator (shift right) - Shr, - /// The `==` operator (equality) - Eq, - /// The `<` operator (less than) - Lt, - /// The `<=` operator (less than or equal to) - Le, - /// The `!=` operator (not equal to) - Ne, - /// The `>=` operator (greater than or equal to) - Ge, - /// The `>` operator (greater than) - Gt, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum UnOp { - /// The `!` operator for logical inversion - Not, - /// The `-` operator for negation - Neg, -} - -impl<'tcx> Debug for Rvalue<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - use self::Rvalue::*; - - match *self { - Use(ref lvalue) => write!(fmt, "{:?}", lvalue), - Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), - Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b), - Len(ref a) => write!(fmt, "LEN({:?})", a), - Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?}", lv, ty, kind), - BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?},{:?})", op, a, b), - UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), - Box(ref t) => write!(fmt, "Box {:?}", t), - Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs), - InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm), - Slice { ref input, from_start, from_end } => - write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end), - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Constants -// -// Two constants are equal if they are the same constant. Note that -// this does not necessarily mean that they are "==" in Rust -- in -// particular one must be wary of `NaN`! - -#[derive(Clone, Debug, PartialEq)] -pub struct Constant<'tcx> { - pub span: Span, - pub ty: Ty<'tcx>, - pub literal: Literal<'tcx>, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum Literal<'tcx> { - Item { - def_id: DefId, - substs: &'tcx Substs<'tcx>, - }, - Value { - value: ConstVal, - }, -} diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs deleted file mode 100644 index 4d034ae23b4..00000000000 --- a/src/librustc_mir/tcx/mod.rs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2015 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. - -/*! - * Methods for the various MIR types. These are intended for use after - * building is complete. - */ - -use repr::*; -use rustc::middle::subst::Substs; -use rustc::middle::ty::{self, AdtDef, Ty}; -use rustc_front::hir; - -#[derive(Copy, Clone, Debug)] -pub enum LvalueTy<'tcx> { - /// Normal type. - Ty { ty: Ty<'tcx> }, - - /// Downcast to a particular variant of an enum. - Downcast { adt_def: AdtDef<'tcx>, - substs: &'tcx Substs<'tcx>, - variant_index: usize }, -} - -impl<'tcx> LvalueTy<'tcx> { - pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> { - LvalueTy::Ty { ty: ty } - } - - pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - match *self { - LvalueTy::Ty { ty } => - ty, - LvalueTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_enum(adt_def, substs), - } - } - - pub fn projection_ty(self, - tcx: &ty::ctxt<'tcx>, - elem: &LvalueElem<'tcx>) - -> LvalueTy<'tcx> - { - match *elem { - ProjectionElem::Deref => - LvalueTy::Ty { - ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference) - .unwrap() - .ty - }, - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => - LvalueTy::Ty { - ty: self.to_ty(tcx).builtin_index().unwrap() - }, - ProjectionElem::Downcast(adt_def1, index) => - match self.to_ty(tcx).sty { - ty::TyEnum(adt_def, substs) => { - assert!(index < adt_def.variants.len()); - assert_eq!(adt_def, adt_def1); - LvalueTy::Downcast { adt_def: adt_def, - substs: substs, - variant_index: index } - } - _ => { - tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self)) - } - }, - ProjectionElem::Field(field) => { - let field_ty = match self { - LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) => - adt_def.struct_variant().fields[field.index()].ty(tcx, substs), - ty::TyTuple(ref tys) => - tys[field.index()], - ty::TyClosure(_, ref closure_substs) => - closure_substs.upvar_tys[field.index()], - _ => - tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)), - }, - LvalueTy::Downcast { adt_def, substs, variant_index } => - adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs), - }; - LvalueTy::Ty { ty: field_ty } - } - } - } -} - -impl<'tcx> Mir<'tcx> { - pub fn operand_ty(&self, - tcx: &ty::ctxt<'tcx>, - operand: &Operand<'tcx>) - -> Ty<'tcx> - { - match *operand { - Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx), - Operand::Constant(ref c) => c.ty, - } - } - - pub fn binop_ty(&self, - tcx: &ty::ctxt<'tcx>, - op: BinOp, - lhs_ty: Ty<'tcx>, - rhs_ty: Ty<'tcx>) - -> Ty<'tcx> - { - // FIXME: handle SIMD correctly - match op { - BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | - BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => { - // these should be integers or floats of the same size. - assert_eq!(lhs_ty, rhs_ty); - lhs_ty - } - BinOp::Shl | BinOp::Shr => { - lhs_ty // lhs_ty can be != rhs_ty - } - BinOp::Eq | BinOp::Lt | BinOp::Le | - BinOp::Ne | BinOp::Ge | BinOp::Gt => { - tcx.types.bool - } - } - } - - pub fn lvalue_ty(&self, - tcx: &ty::ctxt<'tcx>, - lvalue: &Lvalue<'tcx>) - -> LvalueTy<'tcx> - { - match *lvalue { - Lvalue::Var(index) => - LvalueTy::Ty { ty: self.var_decls[index as usize].ty }, - Lvalue::Temp(index) => - LvalueTy::Ty { ty: self.temp_decls[index as usize].ty }, - Lvalue::Arg(index) => - LvalueTy::Ty { ty: self.arg_decls[index as usize].ty }, - Lvalue::Static(def_id) => - LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, - Lvalue::ReturnPointer => - LvalueTy::Ty { ty: self.return_ty.unwrap() }, - Lvalue::Projection(ref proj) => - self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem) - } - } -} - -impl BorrowKind { - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - BorrowKind::Mut => hir::MutMutable, - BorrowKind::Shared => hir::MutImmutable, - - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::MutMutable, - } - } -} - -impl BinOp { - pub fn to_hir_binop(self) -> hir::BinOp_ { - match self { - BinOp::Add => hir::BinOp_::BiAdd, - BinOp::Sub => hir::BinOp_::BiSub, - BinOp::Mul => hir::BinOp_::BiMul, - BinOp::Div => hir::BinOp_::BiDiv, - BinOp::Rem => hir::BinOp_::BiRem, - BinOp::BitXor => hir::BinOp_::BiBitXor, - BinOp::BitAnd => hir::BinOp_::BiBitAnd, - BinOp::BitOr => hir::BinOp_::BiBitOr, - BinOp::Shl => hir::BinOp_::BiShl, - BinOp::Shr => hir::BinOp_::BiShr, - BinOp::Eq => hir::BinOp_::BiEq, - BinOp::Ne => hir::BinOp_::BiNe, - BinOp::Lt => hir::BinOp_::BiLt, - BinOp::Gt => hir::BinOp_::BiGt, - BinOp::Le => hir::BinOp_::BiLe, - BinOp::Ge => hir::BinOp_::BiGe - } - } -} diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index e156fbf004f..1eb3bfd7e02 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -12,8 +12,8 @@ //! We want to do this once just before trans, so trans does not have to take //! care erasing regions all over the place. -use repr::*; use rustc::middle::ty; +use rustc::mir::repr::*; use transform::MirPass; use mir_map::MirMap; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 9bec934143f..174718f7b16 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -12,7 +12,7 @@ pub mod simplify_cfg; pub mod erase_regions; mod util; -use repr::Mir; +use rustc::mir::repr::Mir; pub trait MirPass<'tcx> { fn run_on_mir(&mut self, mir: &mut Mir<'tcx>); diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index ee9dcbf1203..558276a13a8 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use repr::*; use rustc::middle::const_eval::ConstVal; +use rustc::mir::repr::*; use std::mem; use transform::util; use transform::MirPass; diff --git a/src/librustc_mir/transform/util.rs b/src/librustc_mir/transform/util.rs index e45cfa83954..95102694544 100644 --- a/src/librustc_mir/transform/util.rs +++ b/src/librustc_mir/transform/util.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use repr::*; +use rustc::mir::repr::*; /// Update basic block ids in all terminators using the given replacements, /// useful e.g. after removal of several basic blocks to update all terminators diff --git a/src/librustc_mir/visit.rs b/src/librustc_mir/visit.rs index b3ec2f10cf6..bef1850d3c5 100644 --- a/src/librustc_mir/visit.rs +++ b/src/librustc_mir/visit.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::middle::ty::Region; -use repr::*; +use rustc::mir::repr::*; pub trait Visitor<'tcx> { // Override these, and call `self.super_xxx` to revert back to the diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 275f4628788..fa500ab9355 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -40,7 +40,7 @@ use middle::traits; use middle::ty::{self, HasTypeFlags, Ty}; use middle::ty::fold::{TypeFolder, TypeFoldable}; use rustc_front::hir; -use rustc_mir::repr::Mir; +use rustc::mir::repr::Mir; use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; @@ -1223,4 +1223,4 @@ pub fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } else { base::get_extern_const(ccx, did, ty) } -} \ No newline at end of file +} diff --git a/src/librustc_trans/trans/mir/analyze.rs b/src/librustc_trans/trans/mir/analyze.rs index fc76d1e787d..c3e6e0ff56b 100644 --- a/src/librustc_trans/trans/mir/analyze.rs +++ b/src/librustc_trans/trans/mir/analyze.rs @@ -12,7 +12,7 @@ //! which do not. use rustc_data_structures::fnv::FnvHashSet; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use rustc_mir::visit::{Visitor, LvalueContext}; use trans::common::{self, Block}; use super::rvalue; diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 181a03790ee..3ce08fb2f60 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::BasicBlockRef; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use trans::base; use trans::build; use trans::common::Block; diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 9af5bb43318..176cc298f96 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -10,7 +10,7 @@ use middle::ty::{Ty, HasTypeFlags}; use rustc::middle::const_eval::ConstVal; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use trans::consts::{self, TrueConst}; use trans::common::{self, Block}; use trans::common::{C_bool, C_bytes, C_floating_f64, C_integral, C_str_slice}; diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs index 1f39a2aa048..5d9a1e44ac1 100644 --- a/src/librustc_trans/trans/mir/lvalue.rs +++ b/src/librustc_trans/trans/mir/lvalue.rs @@ -10,8 +10,8 @@ use llvm::ValueRef; use rustc::middle::ty::{self, Ty, HasTypeFlags}; -use rustc_mir::repr as mir; -use rustc_mir::tcx::LvalueTy; +use rustc::mir::repr as mir; +use rustc::mir::tcx::LvalueTy; use trans::adt; use trans::base; use trans::build; diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index c8eef7ff448..27c9feaad35 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -10,8 +10,8 @@ use libc::c_uint; use llvm::{self, ValueRef}; -use rustc_mir::repr as mir; -use rustc_mir::tcx::LvalueTy; +use rustc::mir::repr as mir; +use rustc::mir::tcx::LvalueTy; use trans::base; use trans::build; use trans::common::{self, Block}; diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs index 75d7b574382..106c1d05ab7 100644 --- a/src/librustc_trans/trans/mir/operand.rs +++ b/src/librustc_trans/trans/mir/operand.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::middle::ty::{Ty, HasTypeFlags}; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use trans::base; use trans::common::{self, Block}; use trans::datum; diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index cce71b25702..17e4ec8e827 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::middle::ty::{self, Ty}; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use trans::asm; use trans::base; diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs index 95ff049836e..9894626e284 100644 --- a/src/librustc_trans/trans/mir/statement.rs +++ b/src/librustc_trans/trans/mir/statement.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::middle::ty::LvaluePreference; -use rustc_mir::repr as mir; +use rustc::mir::repr as mir; use trans::common::Block; use trans::debuginfo::DebugLoc; use trans::glue; -- cgit 1.4.1-3-g733a5