mod cache;
pub mod tcx;
pub mod visit;
-pub mod transform;
pub mod traversal;
/// Types for locals
/// in scope, but a separate set of locals.
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
- /// Return type of the function.
- pub return_ty: Ty<'tcx>,
-
/// Yield type of the function, if it is a generator.
pub yield_ty: Option<Ty<'tcx>>,
visibility_scope_info: ClearOnDecode<IndexVec<VisibilityScope,
VisibilityScopeInfo>>,
promoted: IndexVec<Promoted, Mir<'tcx>>,
- return_ty: Ty<'tcx>,
yield_ty: Option<Ty<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
arg_count: usize,
// We need `arg_count` locals, and one for the return pointer
assert!(local_decls.len() >= arg_count + 1,
"expected at least {} locals, got {}", arg_count + 1, local_decls.len());
- assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
Mir {
basic_blocks,
visibility_scopes,
visibility_scope_info,
promoted,
- return_ty,
yield_ty,
generator_drop: None,
generator_layout: None,
let block = &self[location.block];
let stmts = &block.statements;
let idx = location.statement_index;
- if location.statement_index < stmts.len() {
+ if idx < stmts.len() {
&stmts[idx].source_info
} else {
- assert!(location.statement_index == stmts.len());
+ assert!(idx == stmts.len());
&block.terminator().source_info
}
}
+
+ /// Return the return type, it always return first element from `local_decls` array
+ pub fn return_ty(&self) -> Ty<'tcx> {
+ self.local_decls[RETURN_POINTER].ty
+ }
}
#[derive(Clone, Debug)]
visibility_scopes,
visibility_scope_info,
promoted,
- return_ty,
yield_ty,
generator_drop,
generator_layout,
///////////////////////////////////////////////////////////////////////////
// Variables and temps
-newtype_index!(Local, "_");
-
-pub const RETURN_POINTER: Local = Local(0);
+newtype_index!(Local
+ {
+ DEBUG_FORMAT = "_{}",
+ const RETURN_POINTER = 0,
+ });
/// Classifies locals into categories. See `Mir::local_kind`.
#[derive(PartialEq, Eq, Debug)]
///////////////////////////////////////////////////////////////////////////
// BasicBlock
-newtype_index!(BasicBlock, "bb");
+newtype_index!(BasicBlock { DEBUG_FORMAT = "bb{}" });
+
+impl BasicBlock {
+ pub fn start_location(self) -> Location {
+ Location {
+ block: self,
+ statement_index: 0,
+ }
+ }
+}
///////////////////////////////////////////////////////////////////////////
// BasicBlockData and Terminator
unwind: Option<BasicBlock>
},
- /// Drop the Lvalue and assign the new value over it
+ /// Drop the Lvalue and assign the new value over it. This ensures
+ /// that the assignment to LV occurs *even if* the destructor for
+ /// lvalue unwinds. Its semantics are best explained by by the
+ /// elaboration:
+ ///
+ /// ```
+ /// BB0 {
+ /// DropAndReplace(LV <- RV, goto BB1, unwind BB2)
+ /// }
+ /// ```
+ ///
+ /// becomes
+ ///
+ /// ```
+ /// BB0 {
+ /// Drop(LV, goto BB1, unwind BB2)
+ /// }
+ /// BB1 {
+ /// // LV is now unitialized
+ /// LV <- RV
+ /// }
+ /// BB2 {
+ /// // LV is now unitialized -- its dtor panicked
+ /// LV <- RV
+ /// }
+ /// ```
DropAndReplace {
location: Lvalue<'tcx>,
value: Operand<'tcx>,
Call {
/// The function that’s being called
func: Operand<'tcx>,
- /// Arguments the function is called with
+ /// Arguments the function is called with.
+ /// These are owned by the callee, which is free to modify them.
+ /// This allows the memory occupied by "by-value" arguments to be
+ /// reused across function calls without duplicating the contents.
args: Vec<Operand<'tcx>>,
/// Destination for the return value. If some, the call is converging.
destination: Option<(Lvalue<'tcx>, BasicBlock)>,
/// Indicates the end of the dropping of a generator
GeneratorDrop,
+
+ FalseEdges {
+ real_target: BasicBlock,
+ imaginary_targets: Vec<BasicBlock>
+ },
}
impl<'tcx> Terminator<'tcx> {
}
Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
Assert { ref target, .. } => slice::ref_slice(target).into_cow(),
+ FalseEdges { ref real_target, ref imaginary_targets } => {
+ let mut s = vec![*real_target];
+ s.extend_from_slice(imaginary_targets);
+ s.into_cow()
+ }
}
}
vec![target]
}
Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind],
- Assert { ref mut target, .. } => vec![target]
+ Assert { ref mut target, .. } => vec![target],
+ FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
+ let mut s = vec![real_target];
+ s.extend(imaginary_targets.iter_mut());
+ s
+ }
}
}
}
}
write!(fmt, ")")
- }
+ },
+ FalseEdges { .. } => write!(fmt, "falseEdges")
}
}
}
Assert { cleanup: None, .. } => vec!["".into()],
Assert { .. } =>
- vec!["success".into_cow(), "unwind".into_cow()]
+ vec!["success".into_cow(), "unwind".into_cow()],
+ FalseEdges { ref imaginary_targets, .. } => {
+ let mut l = vec!["real".into()];
+ l.resize(imaginary_targets.len() + 1, "imaginary".into());
+ l
+ }
}
}
}
/// and the index is a local.
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
-newtype_index!(Field, "field");
+newtype_index!(Field { DEBUG_FORMAT = "field[{}]" });
impl<'tcx> Lvalue<'tcx> {
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Scopes
-newtype_index!(VisibilityScope, "scope");
-pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0);
+newtype_index!(VisibilityScope
+ {
+ DEBUG_FORMAT = "scope[{}]",
+ const ARGUMENT_VISIBILITY_SCOPE = 0,
+ });
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VisibilityScopeData {
pub literal: Literal<'tcx>,
}
-newtype_index!(Promoted, "promoted");
+newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
}
impl Location {
+ /// Returns the location immediately after this one within the enclosing block.
+ ///
+ /// Note that if this location represents a terminator, then the
+ /// resulting location would be out of bounds and invalid.
+ pub fn successor_within_block(&self) -> Location {
+ Location { block: self.block, statement_index: self.statement_index + 1 }
+ }
+
pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool {
if self.block == other.block {
self.statement_index <= other.statement_index
visibility_scopes: self.visibility_scopes.clone(),
visibility_scope_info: self.visibility_scope_info.clone(),
promoted: self.promoted.fold_with(folder),
- return_ty: self.return_ty.fold_with(folder),
yield_ty: self.yield_ty.fold_with(folder),
generator_drop: self.generator_drop.fold_with(folder),
generator_layout: self.generator_layout.fold_with(folder),
self.generator_layout.visit_with(visitor) ||
self.yield_ty.visit_with(visitor) ||
self.promoted.visit_with(visitor) ||
- self.return_ty.visit_with(visitor) ||
self.local_decls.visit_with(visitor)
}
}
Resume => Resume,
Return => Return,
Unreachable => Unreachable,
+ FalseEdges { real_target, ref imaginary_targets } =>
+ FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
};
Terminator {
source_info: self.source_info,
Resume |
Return |
GeneratorDrop |
- Unreachable => false
+ Unreachable |
+ FalseEdges { .. } => false
}
}
}