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/transform | |
| 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/transform')
| -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 |
5 files changed, 141 insertions, 128 deletions
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. |
