diff options
| author | Jonas Schievink <jonasschievink@gmail.com> | 2016-09-25 01:38:27 +0200 |
|---|---|---|
| committer | Jonas Schievink <jonasschievink@gmail.com> | 2016-09-26 20:41:54 +0200 |
| commit | 393db2d83089b3940fa2fe77f1241ca4625fe883 (patch) | |
| tree | 49bcbec475b6668847f8af1d007f8f28e10102b2 /src/librustc_mir | |
| parent | 205dac935531aaf0a5b70898db28e1f1e5f86176 (diff) | |
| download | rust-393db2d83089b3940fa2fe77f1241ca4625fe883.tar.gz rust-393db2d83089b3940fa2fe77f1241ca4625fe883.zip | |
[WIP] Move MIR towards a single kind of local
Diffstat (limited to 'src/librustc_mir')
| -rw-r--r-- | src/librustc_mir/build/expr/as_lvalue.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/build/expr/stmt.rs | 8 | ||||
| -rw-r--r-- | src/librustc_mir/build/matches/mod.rs | 18 | ||||
| -rw-r--r-- | src/librustc_mir/build/misc.rs | 6 | ||||
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 104 | ||||
| -rw-r--r-- | src/librustc_mir/build/scope.rs | 23 | ||||
| -rw-r--r-- | src/librustc_mir/def_use.rs | 60 | ||||
| -rw-r--r-- | src/librustc_mir/graphviz.rs | 27 | ||||
| -rw-r--r-- | src/librustc_mir/pretty.rs | 57 | ||||
| -rw-r--r-- | src/librustc_mir/transform/copy_prop.rs | 67 | ||||
| -rw-r--r-- | src/librustc_mir/transform/instcombine.rs | 7 | ||||
| -rw-r--r-- | src/librustc_mir/transform/promote_consts.rs | 74 | ||||
| -rw-r--r-- | src/librustc_mir/transform/qualify_consts.rs | 98 | ||||
| -rw-r--r-- | src/librustc_mir/transform/type_check.rs | 23 |
14 files changed, 301 insertions, 275 deletions
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index ae5ccbfd820..a9dfc6ea651 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.and(slice.index(idx)) } ExprKind::SelfRef => { - block.and(Lvalue::Arg(Arg::new(0))) + block.and(Lvalue::Local(Local::new(1))) } ExprKind::VarRef { id } => { let index = this.var_indices[&id]; - block.and(Lvalue::Var(index)) + block.and(Lvalue::Local(index)) } ExprKind::StaticRef { id } => { block.and(Lvalue::Static(id)) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8ae23c9103b..9448527e6e6 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -90,9 +90,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Return { value } => { block = match value { - Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)), + Some(value) => { + unpack!(this.into(&Lvalue::Local(RETURN_POINTER), block, value)) + } None => { - this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer); + this.cfg.push_assign_unit(block, + source_info, + &Lvalue::Local(RETURN_POINTER)); block } }; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 1b64b4d0b53..a9ea82140b5 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -123,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { var, subpattern: None, .. } => { self.storage_live_for_bindings(block, &irrefutable_pat); - let lvalue = Lvalue::Var(self.var_indices[&var]); + let lvalue = Lvalue::Local(self.var_indices[&var]); return self.into(&lvalue, block, initializer); } _ => {} @@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pattern: &Pattern<'tcx>) { match *pattern.kind { PatternKind::Binding { var, ref subpattern, .. } => { - let lvalue = Lvalue::Var(self.var_indices[&var]); + let lvalue = Lvalue::Local(self.var_indices[&var]); let source_info = self.source_info(pattern.span); self.cfg.push(block, Statement { source_info: source_info, @@ -705,10 +705,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(binding.span); self.cfg.push(block, Statement { source_info: source_info, - kind: StatementKind::StorageLive(Lvalue::Var(var_index)) + kind: StatementKind::StorageLive(Lvalue::Local(var_index)) }); self.cfg.push_assign(block, source_info, - &Lvalue::Var(var_index), rvalue); + &Lvalue::Local(var_index), rvalue); } } @@ -718,19 +718,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { name: Name, var_id: NodeId, var_ty: Ty<'tcx>) - -> Var + -> Local { debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})", var_id, name, var_ty, source_info); - let var = self.var_decls.push(VarDecl::<'tcx> { - source_info: source_info, + let var = self.local_decls.push(LocalDecl::<'tcx> { mutability: mutability, - name: name, ty: var_ty.clone(), + name: Some(name), + source_info: Some(source_info), }); let extent = self.extent_of_innermost_scope(); - self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty); + self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty); self.var_indices.insert(var_id, var); debug!("declare_binding: var={:?}", var); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 79a4cf73041..4bc51c3a625 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -28,10 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let temp = self.temp_decls.push(TempDecl { ty: ty }); - let lvalue = Lvalue::Temp(temp); + let temp = self.local_decls.push(LocalDecl::new_temp(ty)); + let lvalue = Lvalue::Local(temp); debug!("temp: created temp {:?} with type {:?}", - lvalue, self.temp_decls[temp].ty); + lvalue, self.local_decls[temp].ty); lvalue } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1f8dffe5871..4f531c9a2f8 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -28,6 +28,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { cfg: CFG<'tcx>, fn_span: Span, + arg_count: usize, /// the current set of scopes, updated as we traverse; /// see the `scope` module for more details @@ -49,9 +50,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>, visibility_scope: VisibilityScope, - var_decls: IndexVec<Var, VarDecl<'tcx>>, - var_indices: NodeMap<Var>, - temp_decls: IndexVec<Temp, TempDecl<'tcx>>, + /// Maps node ids of variable bindings to the `Local`s created for them. + var_indices: NodeMap<Local>, + local_decls: IndexVec<Local, LocalDecl<'tcx>>, unit_temp: Option<Lvalue<'tcx>>, /// cached block with the RESUME terminator; this is created @@ -157,9 +158,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)> { + let arguments: Vec<_> = arguments.collect(); + let tcx = hir.tcx(); let span = tcx.map.span(fn_id); - let mut builder = Builder::new(hir, span); + let mut builder = Builder::new(hir, span, arguments.len(), return_ty); let body_id = ast_block.id; let call_site_extent = @@ -169,9 +172,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, tcx.region_maps.lookup_code_extent( CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id }); let mut block = START_BLOCK; - let arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| { - let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| { - builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block) + unpack!(block = builder.in_scope(call_site_extent, block, |builder| { + unpack!(block = builder.in_scope(arg_extent, block, |builder| { + builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block) })); let source_info = builder.source_info(span); @@ -180,7 +183,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, TerminatorKind::Goto { target: return_block }); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); - return_block.and(arg_decls) + return_block.unit() })); assert_eq!(block, builder.return_block()); @@ -217,7 +220,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - let (mut mir, aux) = builder.finish(upvar_decls, arg_decls, return_ty); + let (mut mir, aux) = builder.finish(upvar_decls, return_ty); mir.spread_last_arg = spread_last_arg; (mir, aux) } @@ -227,15 +230,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, ast_expr: &'tcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) { let tcx = hir.tcx(); + let ty = tcx.expr_ty_adjusted(ast_expr); let span = tcx.map.span(item_id); - let mut builder = Builder::new(hir, span); + let mut builder = Builder::new(hir, span, 0, ty); let extent = tcx.region_maps.temporary_scope(ast_expr.id) .unwrap_or(ROOT_CODE_EXTENT); let mut block = START_BLOCK; let _ = builder.in_scope(extent, block, |builder| { let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr)); + unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr)); let source_info = builder.source_info(span); let return_block = builder.return_block(); @@ -247,23 +251,26 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, return_block.unit() }); - let ty = tcx.expr_ty_adjusted(ast_expr); - builder.finish(vec![], IndexVec::new(), ty) + builder.finish(vec![], ty) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> { + fn new(hir: Cx<'a, 'gcx, 'tcx>, + span: Span, + arg_count: usize, + return_ty: Ty<'tcx>) + -> Builder<'a, 'gcx, 'tcx> { let mut builder = Builder { hir: hir, cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, + arg_count: arg_count, scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, scope_auxiliary: IndexVec::new(), loop_scopes: vec![], - temp_decls: IndexVec::new(), - var_decls: IndexVec::new(), + local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -279,7 +286,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec<UpvarDecl>, - arg_decls: IndexVec<Arg, ArgDecl<'tcx>>, return_ty: Ty<'tcx>) -> (Mir<'tcx>, ScopeAuxiliaryVec) { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { @@ -292,27 +298,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scopes, IndexVec::new(), return_ty, - self.var_decls, - arg_decls, - self.temp_decls, + self.local_decls, + self.arg_count, upvar_decls, self.fn_span ), self.scope_auxiliary) } - fn args_and_body<A>(&mut self, - mut block: BasicBlock, - return_ty: Ty<'tcx>, - arguments: A, - argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) - -> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>> - where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)> + fn args_and_body(&mut self, + mut block: BasicBlock, + return_ty: Ty<'tcx>, + arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], + argument_extent: CodeExtent, + ast_block: &'gcx hir::Block) + -> BlockAnd<()> { - // to start, translate the argument patterns and collect the argument types. + // Allocate locals for the function arguments + for &(ty, pattern) in arguments.iter() { + // If this is a simple binding pattern, give the local a nice name for debuginfo. + let mut name = None; + if let Some(pat) = pattern { + if let hir::PatKind::Binding(_, ref ident, _) = pat.node { + name = Some(ident.node); + } + } + + self.local_decls.push(LocalDecl { + mutability: Mutability::Not, + ty: ty, + source_info: None, + name: name, + }); + } + let mut scope = None; - let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| { - let lvalue = Lvalue::Arg(Arg::new(index)); + // Bind the argument patterns + for (index, &(ty, pattern)) in arguments.iter().enumerate() { + // Function arguments always get the first Local indices after the return pointer + let lvalue = Lvalue::Local(Local::new(index + 1)); + if let Some(pattern) = pattern { let pattern = self.hir.irrefutable_pat(pattern); scope = self.declare_bindings(scope, ast_block.span, &pattern); @@ -323,18 +347,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), argument_extent, &lvalue, ty); - let mut name = keywords::Invalid.name(); - if let Some(pat) = pattern { - if let hir::PatKind::Binding(_, ref ident, _) = pat.node { - name = ident.node; - } - } - - ArgDecl { - ty: ty, - debug_name: name - } - }).collect(); + } // Enter the argument pattern bindings visibility scope, if it exists. if let Some(visibility_scope) = scope { @@ -344,9 +357,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // FIXME(#32959): temporary hack for the issue at hand let return_is_unit = return_ty.is_nil(); // start the first basic block and translate the body - unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block)); + unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER), + return_is_unit, block, ast_block)); - block.and(arg_decls) + block.unit() } fn get_unit_temp(&mut self) -> Lvalue<'tcx> { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 0b33e5a1450..88c2c17476e 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -26,7 +26,7 @@ multiple-exit (SEME) region in the control-flow graph. For now, we keep a mapping from each `CodeExtent` to its corresponding SEME region for later reference (see caveat in next paragraph). This is because region scopes are tied to -them. Eventually, when we shift to non-lexical lifetimes, three should +them. Eventually, when we shift to non-lexical lifetimes, there should be no need to remember this mapping. There is one additional wrinkle, actually, that I wanted to hide from @@ -67,7 +67,7 @@ There are numerous "normal" ways to early exit a scope: `break`, early exit occurs, the method `exit_scope` is called. It is given the current point in execution where the early exit occurs, as well as the scope you want to branch to (note that all early exits from to some -other enclosing scope). `exit_scope` will record thid exit point and +other enclosing scope). `exit_scope` will record this exit point and also add all drops. Panics are handled in a similar fashion, except that a panic always @@ -322,7 +322,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.diverge_cleanup(); let scope = self.scopes.pop().unwrap(); assert_eq!(scope.extent, extent); - unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block)); + unpack!(block = build_scope_drops(&mut self.cfg, + &scope, + &self.scopes, + block, + self.arg_count)); self.scope_auxiliary[scope.id] .postdoms .push(self.cfg.current_location(block)); @@ -362,7 +366,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope.cached_exits.insert((target, extent), b); b }; - unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block)); + unpack!(block = build_scope_drops(&mut self.cfg, + scope, + rest, + block, + self.arg_count)); if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), &tmp, free_data, next); @@ -454,7 +462,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { // Only temps and vars need their storage dead. match *lvalue { - Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage, + Lvalue::Local(index) if index.index() > self.arg_count + 1 => DropKind::Storage, _ => return } }; @@ -671,7 +679,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, scope: &Scope<'tcx>, earlier_scopes: &[Scope<'tcx>], - mut block: BasicBlock) + mut block: BasicBlock, + arg_count: usize) -> BlockAnd<()> { let mut iter = scope.drops.iter().rev().peekable(); while let Some(drop_data) = iter.next() { @@ -703,7 +712,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, DropKind::Storage => { // Only temps and vars need their storage dead. match drop_data.location { - Lvalue::Temp(_) | Lvalue::Var(_) => {} + Lvalue::Local(index) if index.index() > arg_count => {} _ => continue } diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/def_use.rs index 11b4441c846..343d802119e 100644 --- a/src/librustc_mir/def_use.rs +++ b/src/librustc_mir/def_use.rs @@ -12,13 +12,12 @@ use rustc::mir::repr::{Local, Location, Lvalue, Mir}; use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::indexed_vec::IndexVec; use std::marker::PhantomData; use std::mem; pub struct DefUseAnalysis<'tcx> { info: IndexVec<Local, Info<'tcx>>, - mir_summary: MirSummary, } #[derive(Clone)] @@ -35,15 +34,13 @@ pub struct Use<'tcx> { impl<'tcx> DefUseAnalysis<'tcx> { pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { DefUseAnalysis { - info: IndexVec::from_elem_n(Info::new(), mir.count_locals()), - mir_summary: MirSummary::new(mir), + info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()), } } pub fn analyze(&mut self, mir: &Mir<'tcx>) { let mut finder = DefUseFinder { info: mem::replace(&mut self.info, IndexVec::new()), - mir_summary: self.mir_summary, }; finder.visit_mir(mir); self.info = finder.info @@ -64,7 +61,6 @@ impl<'tcx> DefUseAnalysis<'tcx> { for lvalue_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, &mut callback, - self.mir_summary, mir).visit_location(mir, lvalue_use.location) } } @@ -80,13 +76,17 @@ impl<'tcx> DefUseAnalysis<'tcx> { struct DefUseFinder<'tcx> { info: IndexVec<Local, Info<'tcx>>, - mir_summary: MirSummary, } impl<'tcx> DefUseFinder<'tcx> { fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> { let info = &mut self.info; - self.mir_summary.local_index(lvalue).map(move |local| &mut info[local]) + + if let Lvalue::Local(local) = *lvalue { + Some(&mut info[local]) + } else { + None + } } } @@ -132,18 +132,16 @@ impl<'tcx> Info<'tcx> { struct MutateUseVisitor<'tcx, F> { query: Local, callback: F, - mir_summary: MirSummary, phantom: PhantomData<&'tcx ()>, } impl<'tcx, F> MutateUseVisitor<'tcx, F> { - fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>) + fn new(query: Local, callback: F, _: &Mir<'tcx>) -> MutateUseVisitor<'tcx, F> where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { MutateUseVisitor { query: query, callback: callback, - mir_summary: mir_summary, phantom: PhantomData, } } @@ -155,43 +153,11 @@ impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if self.mir_summary.local_index(lvalue) == Some(self.query) { - (self.callback)(lvalue, context, location) - } - self.super_lvalue(lvalue, context, location) - } -} - -/// A small structure that enables various metadata of the MIR to be queried -/// without a reference to the MIR itself. -#[derive(Clone, Copy)] -pub struct MirSummary { - arg_count: usize, - var_count: usize, - temp_count: usize, -} - -impl MirSummary { - pub fn new(mir: &Mir) -> MirSummary { - MirSummary { - arg_count: mir.arg_decls.len(), - var_count: mir.var_decls.len(), - temp_count: mir.temp_decls.len(), - } - } - - pub fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> { - match *lvalue { - Lvalue::Arg(arg) => Some(Local::new(arg.index())), - Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)), - Lvalue::Temp(temp) => { - Some(Local::new(temp.index() + self.arg_count + self.var_count)) + if let Lvalue::Local(local) = *lvalue { + if local == self.query { + (self.callback)(lvalue, context, location) } - Lvalue::ReturnPointer => { - Some(Local::new(self.arg_count + self.var_count + self.temp_count)) - } - _ => None, } + self.super_lvalue(lvalue, context, location) } } - diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index 72b6d7f0e5a..b80e11a63db 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -136,30 +136,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write!(w, " label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?; // fn argument types. - for (i, arg) in mir.arg_decls.iter().enumerate() { + for (i, arg) in mir.arg_iter().enumerate() { if i > 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?; + write!(w, "{:?}: {}", Lvalue::Local(arg), escape(&mir.local_decls[arg].ty))?; } write!(w, ") -> {}", escape(mir.return_ty))?; write!(w, r#"<br align="left"/>"#)?; - // User variable types (including the user's name in a comment). - for (i, var) in mir.var_decls.iter().enumerate() { + for local in mir.var_and_temp_iter() { + let decl = &mir.local_decls[local]; + write!(w, "let ")?; - if var.mutability == Mutability::Mut { + if decl.mutability == Mutability::Mut { write!(w, "mut ")?; } - write!(w, r#"{:?}: {}; // {}<br align="left"/>"#, - Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?; - } - // Compiler-introduced temporary types. - for (i, temp) in mir.temp_decls.iter().enumerate() { - write!(w, r#"let mut {:?}: {};<br align="left"/>"#, - Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?; + if let Some(name) = decl.name { + write!(w, r#"{:?}: {}; // {}<br align="left"/>"#, + Lvalue::Local(local), escape(&decl.ty), name)?; + } else { + write!(w, r#"let mut {:?}: {};<br align="left"/>"#, + Lvalue::Local(local), escape(&decl.ty))?; + } } writeln!(w, ">;") @@ -172,3 +173,5 @@ fn node(block: BasicBlock) -> String { fn escape<T: Debug>(t: &T) -> String { dot::escape_html(&format!("{:?}", t)) } + +// TODO manually test diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 01e2c6308ba..b687c52447c 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -214,6 +214,9 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) } +/// Prints user-defined variables in a scope tree. +/// +/// Returns the total number of variables printed. fn write_scope_tree(tcx: TyCtxt, mir: &Mir, scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>, @@ -234,11 +237,14 @@ fn write_scope_tree(tcx: TyCtxt, writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; // User variable types (including the user's name in a comment). - for (id, var) in mir.var_decls.iter_enumerated() { - // Skip if not declared in this scope. - if var.source_info.scope != child { + for local in mir.var_iter() { + let var = &mir.local_decls[local]; + let (name, source_info) = if var.source_info.unwrap().scope == child { + (var.name.unwrap(), var.source_info.unwrap()) + } else { + // Not a variable or not declared in this scope. continue; - } + }; let mut_str = if var.mutability == Mutability::Mut { "mut " @@ -251,13 +257,13 @@ fn write_scope_tree(tcx: TyCtxt, INDENT, indent, mut_str, - id, + local, var.ty); writeln!(w, "{0:1$} // \"{2}\" in {3}", indented_var, ALIGN, - var.name, - comment(tcx, var.source_info))?; + name, + comment(tcx, source_info))?; } write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; @@ -291,9 +297,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Print return pointer + let indented_retptr = format!("{}let mut {:?}: {};", + INDENT, + RETURN_POINTER, + mir.return_ty); + writeln!(w, "{0:1$} // return pointer", + indented_retptr, + ALIGN)?; + write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?; - write_mir_decls(mir, w) + write_temp_decls(mir, w)?; + + // Add an empty line before the first block is printed. + writeln!(w, "")?; + + Ok(()) } fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) @@ -313,30 +333,27 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, "(")?; // fn argument types. - for (i, arg) in mir.arg_decls.iter_enumerated() { - if i.index() != 0 { + for (i, arg) in mir.arg_iter().enumerate() { + if i != 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?; + write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?; } write!(w, ") -> {}", mir.return_ty) } else { - assert!(mir.arg_decls.is_empty()); + assert_eq!(mir.arg_count, 0); write!(w, ": {} =", mir.return_ty) } } -fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { +fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { // Compiler-introduced temporary types. - for (id, temp) in mir.temp_decls.iter_enumerated() { - writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?; - } - - // Wrote any declaration? Add an empty line before the first block is printed. - if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() { - writeln!(w, "")?; + for temp in mir.temp_iter() { + writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?; } Ok(()) } + +// TODO manually test diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 79fd16012d9..783162cd558 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,12 +29,11 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use def_use::{DefUseAnalysis, MirSummary}; +use def_use::DefUseAnalysis; use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; -use rustc_data_structures::indexed_vec::Idx; use transform::qualify_consts; pub struct CopyPropagation; @@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { def_use_analysis.analyze(mir); let mut changed = false; - for dest_local_index in 0..mir.count_locals() { - let dest_local = Local::new(dest_local_index); - debug!("Considering destination local: {}", mir.format_local(dest_local)); + for dest_local in mir.local_decls.indices() { + debug!("Considering destination local: {:?}", dest_local); let action; let location; @@ -89,19 +87,19 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { let dest_use_info = def_use_analysis.local_info(dest_local); let dest_def_count = dest_use_info.def_count_not_including_drop(); if dest_def_count == 0 { - debug!(" Can't copy-propagate local: dest {} undefined", - mir.format_local(dest_local)); + debug!(" Can't copy-propagate local: dest {:?} undefined", + dest_local); continue } if dest_def_count > 1 { - debug!(" Can't copy-propagate local: dest {} defined {} times", - mir.format_local(dest_local), + debug!(" Can't copy-propagate local: dest {:?} defined {} times", + dest_local, dest_use_info.def_count()); continue } if dest_use_info.use_count() == 0 { - debug!(" Can't copy-propagate local: dest {} unused", - mir.format_local(dest_local)); + debug!(" Can't copy-propagate local: dest {:?} unused", + dest_local); continue } let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| { @@ -121,11 +119,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { // That use of the source must be an assignment. match statement.kind { - StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if - Some(dest_local) == mir.local_index(dest_lvalue) => { + StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if + local == dest_local => { let maybe_action = match *operand { Operand::Consume(ref src_lvalue) => { - Action::local_copy(mir, &def_use_analysis, src_lvalue) + Action::local_copy(&def_use_analysis, src_lvalue) } Operand::Constant(ref src_constant) => { Action::constant(src_constant) @@ -162,15 +160,14 @@ enum Action<'tcx> { } impl<'tcx> Action<'tcx> { - fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>) + fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>) -> Option<Action<'tcx>> { // The source must be a local. - let src_local = match mir.local_index(src_lvalue) { - Some(src_local) => src_local, - None => { - debug!(" Can't copy-propagate local: source is not a local"); - return None - } + let src_local = if let Lvalue::Local(local) = *src_lvalue { + local + } else { + debug!(" Can't copy-propagate local: source is not a local"); + return None; }; // We're trying to copy propagate a local. @@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> { // First, remove all markers. // // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!(" Replacing all uses of {} with {} (local)", - mir.format_local(dest_local), - mir.format_local(src_local)); + debug!(" Replacing all uses of {:?} with {:?} (local)", + dest_local, + src_local); for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses { if lvalue_use.context.is_storage_marker() { mir.make_statement_nop(lvalue_use.location) @@ -240,7 +237,7 @@ impl<'tcx> Action<'tcx> { } // Replace all uses of the destination local with the source local. - let src_lvalue = Lvalue::from_local(mir, src_local); + let src_lvalue = Lvalue::Local(src_local); def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue); // Finally, zap the now-useless assignment instruction. @@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> { // First, remove all markers. // // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!(" Replacing all uses of {} with {:?} (constant)", - mir.format_local(dest_local), + debug!(" Replacing all uses of {:?} with {:?} (constant)", + dest_local, src_constant); let dest_local_info = def_use_analysis.local_info(dest_local); for lvalue_use in &dest_local_info.defs_and_uses { @@ -264,8 +261,7 @@ impl<'tcx> Action<'tcx> { } // Replace all uses of the destination local with the constant. - let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir), - dest_local, + let mut visitor = ConstantPropagationVisitor::new(dest_local, src_constant); for dest_lvalue_use in &dest_local_info.defs_and_uses { visitor.visit_location(mir, dest_lvalue_use.location) @@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> { struct ConstantPropagationVisitor<'tcx> { dest_local: Local, constant: Constant<'tcx>, - mir_summary: MirSummary, uses_replaced: usize, } impl<'tcx> ConstantPropagationVisitor<'tcx> { - fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>) + fn new(dest_local: Local, constant: Constant<'tcx>) -> ConstantPropagationVisitor<'tcx> { ConstantPropagationVisitor { dest_local: dest_local, constant: constant, - mir_summary: mir_summary, uses_replaced: 0, } } @@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { self.super_operand(operand, location); match *operand { - Operand::Consume(ref lvalue) => { - if self.mir_summary.local_index(lvalue) != Some(self.dest_local) { - return - } - } - Operand::Constant(_) => return, + Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {} + _ => return, } *operand = Operand::Constant(self.constant.clone()); self.uses_replaced += 1 } } - diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a0331f03b01..b4159af6f07 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -10,11 +10,12 @@ //! Performs various peephole optimizations. -use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue}; +use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::TyCtxt; use rustc::util::nodemap::FnvHashSet; +use rustc_data_structures::indexed_vec::Idx; use std::mem; pub struct InstCombine { @@ -61,7 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for InstCombine { debug!("Replacing `&*`: {:?}", rvalue); let new_lvalue = match *rvalue { Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => { - mem::replace(&mut projection.base, Lvalue::ReturnPointer) + // Replace with dummy + mem::replace(&mut projection.base, Lvalue::Local(Local::new(0))) } _ => bug!("Detected `&*` but didn't find `&*`!"), }; @@ -107,4 +109,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { struct OptimizationList { and_stars: FnvHashSet<Location>, } - diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57de68fce1d..939531a16bc 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -30,6 +30,7 @@ use syntax_pos::Span; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use std::iter; use std::mem; use std::usize; @@ -74,15 +75,21 @@ pub enum Candidate { ShuffleIndices(BasicBlock) } -struct TempCollector { - temps: IndexVec<Temp, TempState>, - span: Span +struct TempCollector<'tcx> { + temps: IndexVec<Local, TempState>, + span: Span, + mir: &'tcx Mir<'tcx>, } -impl<'tcx> Visitor<'tcx> for TempCollector { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { +impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { self.super_lvalue(lvalue, context, location); - if let Lvalue::Temp(index) = *lvalue { + if let Lvalue::Local(index) = *lvalue { + // We're only interested in temporaries + if self.mir.local_kind(index) != LocalKind::Temp { + return; + } + // Ignore drops, if the temp gets promoted, // then it's constant and thus drop is noop. // Storage live ranges are also irrelevant. @@ -126,10 +133,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector { } } -pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> { +pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, TempState> { let mut collector = TempCollector { - temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls), - span: mir.span + temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls), + span: mir.span, + mir: mir, }; for (bb, data) in rpo { collector.visit_basic_block_data(bb, data); @@ -140,7 +148,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, Te struct Promoter<'a, 'tcx: 'a> { source: &'a mut Mir<'tcx>, promoted: Mir<'tcx>, - temps: &'a mut IndexVec<Temp, TempState>, + temps: &'a mut IndexVec<Local, TempState>, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. @@ -177,7 +185,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Copy the initialization of this temp to the /// promoted MIR, recursing through temps. - fn promote_temp(&mut self, temp: Temp) -> Temp { + fn promote_temp(&mut self, temp: Local) -> Local { let old_keep_original = self.keep_original; let (bb, stmt_idx) = match self.temps[temp] { TempState::Defined { @@ -259,20 +267,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }); } - let new_temp = self.promoted.temp_decls.push(TempDecl { - ty: self.source.temp_decls[temp].ty - }); + let new_temp = self.promoted.local_decls.push( + LocalDecl::new_temp(self.source.local_decls[temp].ty)); // Inject the Rvalue or Call into the promoted MIR. if stmt_idx < no_stmts { - self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span); + self.assign(Lvalue::Local(new_temp), rvalue.unwrap(), source_info.span); } else { let last = self.promoted.basic_blocks().last().unwrap(); let new_target = self.new_block(); let mut call = call.unwrap(); match call { TerminatorKind::Call { ref mut destination, ..} => { - *destination = Some((Lvalue::Temp(new_temp), new_target)); + *destination = Some((Lvalue::Local(new_temp), new_target)); } _ => bug!() } @@ -315,11 +322,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } } }; - self.visit_rvalue(&mut rvalue, Location{ + self.visit_rvalue(&mut rvalue, Location { block: BasicBlock::new(0), statement_index: usize::MAX }); - self.assign(Lvalue::ReturnPointer, rvalue, span); + + self.assign(Lvalue::Local(RETURN_POINTER), rvalue, span); self.source.promoted.push(self.promoted); } } @@ -330,8 +338,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if let Lvalue::Temp(ref mut temp) = *lvalue { - *temp = self.promote_temp(*temp); + if let Lvalue::Local(ref mut temp) = *lvalue { + if self.source.local_kind(*temp) == LocalKind::Temp { + *temp = self.promote_temp(*temp); + } } self.super_lvalue(lvalue, context, location); } @@ -339,7 +349,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut temps: IndexVec<Temp, TempState>, + mut temps: IndexVec<Local, TempState>, candidates: Vec<Candidate>) { // Visit candidates in reverse, in case they're nested. for candidate in candidates.into_iter().rev() { @@ -353,7 +363,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, "expected assignment to promote"); } }; - if let Lvalue::Temp(index) = *dest { + if let Lvalue::Local(index) = *dest { if temps[index] == TempState::PromotedOut { // Already promoted. continue; @@ -376,8 +386,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } }; + // Declare return pointer local + let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect(); + let mut promoter = Promoter { - source: mir, promoted: Mir::new( IndexVec::new(), Some(VisibilityScopeData { @@ -386,12 +398,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }).into_iter().collect(), IndexVec::new(), ty, - IndexVec::new(), - IndexVec::new(), - IndexVec::new(), + initial_locals, + 0, vec![], span ), + source: mir, temps: &mut temps, keep_original: false }; @@ -400,13 +412,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } // Eliminate assignments to, and drops of promoted temps. - let promoted = |index: Temp| temps[index] == TempState::PromotedOut; + let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in mir.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Lvalue::Temp(index), _) | - StatementKind::StorageLive(Lvalue::Temp(index)) | - StatementKind::StorageDead(Lvalue::Temp(index)) => { + StatementKind::Assign(Lvalue::Local(index), _) | + StatementKind::StorageLive(Lvalue::Local(index)) | + StatementKind::StorageDead(Lvalue::Local(index)) => { !promoted(index) } _ => true @@ -414,7 +426,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }); let terminator = block.terminator_mut(); match terminator.kind { - TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => { + TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => { if promoted(index) { terminator.kind = TerminatorKind::Goto { target: target diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2c03af2c8e9..acc3084c906 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { param_env: ty::ParameterEnvironment<'tcx>, qualif_map: &'a mut DefIdMap<Qualif>, mir_map: Option<&'a MirMap<'tcx>>, - temp_qualif: IndexVec<Temp, Option<Qualif>>, + temp_qualif: IndexVec<Local, Option<Qualif>>, return_qualif: Option<Qualif>, qualif: Qualif, const_fn_arg_vars: BitVector, - temp_promotion_state: IndexVec<Temp, TempState>, + temp_promotion_state: IndexVec<Local, TempState>, promotion_candidates: Vec<Candidate> } @@ -173,10 +173,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { param_env: param_env, qualif_map: qualif_map, mir_map: mir_map, - temp_qualif: IndexVec::from_elem(None, &mir.temp_decls), + temp_qualif: IndexVec::from_elem(None, &mir.local_decls), return_qualif: None, qualif: Qualif::empty(), - const_fn_arg_vars: BitVector::new(mir.var_decls.len()), + const_fn_arg_vars: BitVector::new(mir.local_decls.len()), temp_promotion_state: temps, promotion_candidates: vec![] } @@ -332,8 +332,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // Only handle promotable temps in non-const functions. if self.mode == Mode::Fn { - if let Lvalue::Temp(index) = *dest { - if self.temp_promotion_state[index].is_promotable() { + if let Lvalue::Local(index) = *dest { + if self.mir.local_kind(index) == LocalKind::Temp + && self.temp_promotion_state[index].is_promotable() { + debug!("store to promotable temp {:?}", index); store(&mut self.temp_qualif[index]); } } @@ -341,13 +343,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } match *dest { - Lvalue::Temp(index) => store(&mut self.temp_qualif[index]), - Lvalue::ReturnPointer => store(&mut self.return_qualif), + Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => { + debug!("store to temp {:?}", index); + store(&mut self.temp_qualif[index]) + } + Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => { + debug!("store to return pointer {:?}", index); + store(&mut self.return_qualif) + } Lvalue::Projection(box Projection { - base: Lvalue::Temp(index), + base: Lvalue::Local(index), elem: ProjectionElem::Deref - }) if self.mir.temp_decls[index].ty.is_unique() + }) if self.mir.local_kind(index) == LocalKind::Temp + && self.mir.local_decls[index].ty.is_unique() && self.temp_qualif[index].map_or(false, |qualif| { qualif.intersects(Qualif::NOT_CONST) }) => { @@ -366,6 +375,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// Qualify a whole const, static initializer or const fn. fn qualify_const(&mut self) -> Qualif { + debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id)); + let mir = self.mir; let mut seen_blocks = BitVector::new(mir.basic_blocks().len()); @@ -399,7 +410,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::Return => { // Check for unused values. This usually means // there are extra statements in the AST. - for temp in mir.temp_decls.indices() { + for temp in mir.temp_iter() { if self.temp_qualif[temp].is_none() { continue; } @@ -424,9 +435,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // Make sure there are no extra unassigned variables. self.qualif = Qualif::NOT_CONST; - for index in 0..mir.var_decls.len() { - if !self.const_fn_arg_vars.contains(index) { - self.assign(&Lvalue::Var(Var::new(index)), Location { + for index in mir.var_iter() { + if !self.const_fn_arg_vars.contains(index.index()) { + debug!("unassigned variable {:?}", index); + self.assign(&Lvalue::Local(index), Location { block: bb, statement_index: usize::MAX, }); @@ -480,23 +492,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { context: LvalueContext<'tcx>, location: Location) { match *lvalue { - Lvalue::Arg(_) => { - self.add(Qualif::FN_ARGUMENT); - } - Lvalue::Var(_) => { - self.add(Qualif::NOT_CONST); - } - Lvalue::Temp(index) => { - if !self.temp_promotion_state[index].is_promotable() { - self.add(Qualif::NOT_PROMOTABLE); + Lvalue::Local(local) => match self.mir.local_kind(local) { + LocalKind::ReturnPointer => { + self.not_const(); + } + LocalKind::Arg => { + self.add(Qualif::FN_ARGUMENT); + } + LocalKind::Var => { + self.add(Qualif::NOT_CONST); } + LocalKind::Temp => { + if !self.temp_promotion_state[local].is_promotable() { + self.add(Qualif::NOT_PROMOTABLE); + } - if let Some(qualif) = self.temp_qualif[index] { - self.add(qualif); - } else { - self.not_const(); + if let Some(qualif) = self.temp_qualif[local] { + self.add(qualif); + } else { + self.not_const(); + } } - } + }, Lvalue::Static(_) => { self.add(Qualif::STATIC); if self.mode == Mode::Const || self.mode == Mode::ConstFn { @@ -505,9 +522,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { a constant instead", self.mode); } } - Lvalue::ReturnPointer => { - self.not_const(); - } Lvalue::Projection(ref proj) => { self.nest(|this| { this.super_lvalue(lvalue, context, location); @@ -685,8 +699,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if self.mode == Mode::Fn || self.mode == Mode::ConstFn { if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { // We can only promote direct borrows of temps. - if let Lvalue::Temp(_) = *lvalue { - self.promotion_candidates.push(candidate); + if let Lvalue::Local(local) = *lvalue { + if self.mir.local_kind(local) == LocalKind::Temp { + self.promotion_candidates.push(candidate); + } } } } @@ -879,17 +895,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.visit_rvalue(rvalue, location); // Check the allowed const fn argument forms. - if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) { - if self.const_fn_arg_vars.insert(index.index()) { + if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) { + if self.mir.local_kind(index) == LocalKind::Var && + self.const_fn_arg_vars.insert(index.index()) { + // Direct use of an argument is permitted. - if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue { - return; + if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue { + if self.mir.local_kind(local) == LocalKind::Arg { + return; + } } // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { - let decl = &self.mir.var_decls[index]; - span_err!(self.tcx.sess, decl.source_info.span, E0022, + let decl = &self.mir.local_decls[index]; + span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7b6a2f55808..7a682292429 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -90,14 +90,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn visit_mir(&mut self, mir: &Mir<'tcx>) { self.sanitize_type(&"return type", mir.return_ty); - for var_decl in &mir.var_decls { - self.sanitize_type(var_decl, var_decl.ty); - } - for (n, arg_decl) in mir.arg_decls.iter().enumerate() { - self.sanitize_type(&(n, arg_decl), arg_decl.ty); - } - for (n, tmp_decl) in mir.temp_decls.iter().enumerate() { - self.sanitize_type(&(n, tmp_decl), tmp_decl.ty); + for local_decl in &mir.local_decls { + self.sanitize_type(local_decl, local_decl.ty); } if self.errors_reported { return; @@ -131,14 +125,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { - Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty }, - Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty }, - Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty }, + Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(def_id) => LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, - Lvalue::ReturnPointer => { - LvalueTy::Ty { ty: self.mir.return_ty } - } Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { @@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::StorageLive(ref lv) | StatementKind::StorageDead(ref lv) => { match *lv { - Lvalue::Temp(_) | Lvalue::Var(_) => {} + Lvalue::Local(_) => {} _ => { - span_mirbug!(self, stmt, "bad lvalue: expected temp or var"); + span_mirbug!(self, stmt, "bad lvalue: expected local"); } } } @@ -711,6 +700,8 @@ impl TypeckMir { impl<'tcx> MirPass<'tcx> for TypeckMir { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { + debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. |
