//! initialization and can otherwise silence errors, if
//! move analysis runs after promotion on broken MIR.
+use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
use rustc::mir::traversal::ReversePostorder;
+use rustc::ty::subst::InternalSubsts;
use rustc::ty::TyCtxt;
use syntax_pos::Span;
/// Borrow of a constant temporary.
Ref(Location),
+ /// Promotion of the `x` in `[x; 32]`.
+ Repeat(Location),
+
/// Currently applied to function calls where the callee has the unstable
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
/// intrinsic. The intrinsic requires the arguments are indeed constant and
new_temp
}
- fn promote_candidate(mut self, candidate: Candidate) {
+ fn promote_candidate(
+ mut self,
+ def_id: DefId,
+ candidate: Candidate,
+ next_promoted_id: usize,
+ ) -> Option<Body<'tcx>> {
let mut operand = {
let promoted = &mut self.promoted;
- let promoted_id = Promoted::new(self.source.promoted.len());
- let mut promoted_place = |ty, span| {
+ let promoted_id = Promoted::new(next_promoted_id);
+ let mut promoted_place = |ty, substs, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
- Place::Base(
- PlaceBase::Static(box Static{ kind: StaticKind::Promoted(promoted_id), ty })
- )
+ Place {
+ base: PlaceBase::Static(box Static {
+ kind: StaticKind::Promoted(promoted_id, substs),
+ ty,
+ def_id,
+ }),
+ projection: None,
+ }
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
match candidate {
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
match statement.kind {
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
- // Find the underlying local for this (necessarily interior) borrow.
- let mut place = place;
- while let Place::Projection(ref mut proj) = *place {
- assert_ne!(proj.elem, ProjectionElem::Deref);
- place = &mut proj.base;
- };
-
- let ty = place.ty(local_decls, self.tcx).ty;
+ // Use the underlying local for this (necessarily interior) borrow.
+ let ty = place.base.ty(local_decls).ty;
let span = statement.source_info.span;
- Operand::Move(mem::replace(place, promoted_place(ty, span)))
+ Operand::Move(Place {
+ base: mem::replace(
+ &mut place.base,
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span,
+ ).base
+ ),
+ projection: None,
+ })
}
_ => bug!()
}
}
+ Candidate::Repeat(loc) => {
+ let ref mut statement = blocks[loc.block].statements[loc.statement_index];
+ match statement.kind {
+ StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
+ let ty = operand.ty(local_decls, self.tcx);
+ let span = statement.source_info.span;
+ mem::replace(
+ operand,
+ Operand::Copy(
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span,
+ )
+ )
+ )
+ }
+ _ => bug!()
+ }
+ },
Candidate::Argument { bb, index } => {
let terminator = blocks[bb].terminator_mut();
match terminator.kind {
TerminatorKind::Call { ref mut args, .. } => {
let ty = args[index].ty(local_decls, self.tcx);
let span = terminator.source_info.span;
- let operand = Operand::Copy(promoted_place(ty, span));
+ let operand =
+ Operand::Copy(
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span));
mem::replace(&mut args[index], operand)
}
// We expected a `TerminatorKind::Call` for which we'd like to promote an
// a function requiring a constant argument and as that constant value
// providing a value whose computation contains another call to a function
// requiring a constant argument.
- TerminatorKind::Goto { .. } => return,
+ TerminatorKind::Goto { .. } => return None,
_ => bug!()
}
}
let span = self.promoted.span;
self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
- self.source.promoted.push(self.promoted);
+ Some(self.promoted)
}
}
}
pub fn promote_candidates<'tcx>(
+ def_id: DefId,
body: &mut Body<'tcx>,
tcx: TyCtxt<'tcx>,
mut temps: IndexVec<Local, TempState>,
candidates: Vec<Candidate>,
-) {
+) -> IndexVec<Promoted, Body<'tcx>> {
// Visit candidates in reverse, in case they're nested.
debug!("promote_candidates({:?})", candidates);
+ let mut promotions = IndexVec::new();
+
for candidate in candidates.into_iter().rev() {
match candidate {
+ Candidate::Repeat(Location { block, statement_index }) |
Candidate::Ref(Location { block, statement_index }) => {
match body[block].statements[statement_index].kind {
- StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _) => {
+ StatementKind::Assign(Place {
+ base: PlaceBase::Local(local),
+ projection: None,
+ }, _) => {
if temps[local] == TempState::PromotedOut {
// Already promoted.
continue;
// memory usage?
body.source_scopes.clone(),
body.source_scope_local_data.clone(),
- IndexVec::new(),
None,
initial_locals,
IndexVec::new(),
temps: &mut temps,
keep_original: false
};
- promoter.promote_candidate(candidate);
+
+ if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) {
+ promotions.push(promoted);
+ }
}
// Eliminate assignments to, and drops of promoted temps.
for block in body.basic_blocks_mut() {
block.statements.retain(|statement| {
match statement.kind {
- StatementKind::Assign(Place::Base(PlaceBase::Local(index)), _) |
+ StatementKind::Assign(Place {
+ base: PlaceBase::Local(index),
+ projection: None,
+ }, _) |
StatementKind::StorageLive(index) |
StatementKind::StorageDead(index) => {
!promoted(index)
});
let terminator = block.terminator_mut();
match terminator.kind {
- TerminatorKind::Drop { location: Place::Base(PlaceBase::Local(index)), target, .. } => {
+ TerminatorKind::Drop { location: Place {
+ base: PlaceBase::Local(index),
+ projection: None,
+ }, target, .. } => {
if promoted(index) {
terminator.kind = TerminatorKind::Goto {
target,
_ => {}
}
}
+
+ promotions
}