Auto merge of #32202 - arielb1:slice-patterns, r=nikomatsakis
Implement RFC495 semantics for slice patterns non-MIR translation is still not supported for these and will happily ICE. This is a [breaking-change] for many uses of slice_patterns. [RFC 495 text](https://github.com/rust-lang/rfcs/blob/master/text/0495-array-pattern-changes.md)
This commit is contained in:
commit
bb4b3fb7f9
77 changed files with 940 additions and 738 deletions
|
|
@ -106,6 +106,7 @@ pub mod mir {
|
|||
pub mod tcx;
|
||||
pub mod visit;
|
||||
pub mod transform;
|
||||
pub mod traversal;
|
||||
pub mod mir_map;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -993,40 +993,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
PatKind::Vec(_, Some(ref slice_pat), _) => {
|
||||
// The `slice_pat` here creates a slice into
|
||||
// the original vector. This is effectively a
|
||||
// borrow of the elements of the vector being
|
||||
// matched.
|
||||
|
||||
let (slice_cmt, slice_mutbl, slice_r) =
|
||||
return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));
|
||||
|
||||
// Note: We declare here that the borrow
|
||||
// occurs upon entering the `[...]`
|
||||
// pattern. This implies that something like
|
||||
// `[a; b]` where `a` is a move is illegal,
|
||||
// because the borrow is already in effect.
|
||||
// In fact such a move would be safe-ish, but
|
||||
// it effectively *requires* that we use the
|
||||
// nulling out semantics to indicate when a
|
||||
// value has been moved, which we are trying
|
||||
// to move away from. Otherwise, how can we
|
||||
// indicate that the first element in the
|
||||
// vector has been moved? Eventually, we
|
||||
// could perhaps modify this rule to permit
|
||||
// `[..a, b]` where `b` is a move, because in
|
||||
// that case we can adjust the length of the
|
||||
// original vec accordingly, but we'd have to
|
||||
// make trans do the right thing, and it would
|
||||
// only work for `Box<[T]>`s. It seems simpler
|
||||
// to just require that people call
|
||||
// `vec.pop()` or `vec.unshift()`.
|
||||
let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
|
||||
delegate.borrow(pat.id, pat.span,
|
||||
slice_cmt, slice_r,
|
||||
slice_bk, RefBinding);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -228,10 +228,10 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
|
|||
Ok(deref_interior(InteriorField(PositionalField(0))))
|
||||
}
|
||||
|
||||
ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
|
||||
ty::TyArray(_, _) | ty::TySlice(_) => {
|
||||
// no deref of indexed content without supplying InteriorOffsetKind
|
||||
if let Some(context) = context {
|
||||
Ok(deref_interior(InteriorElement(context, element_kind(t))))
|
||||
Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
|
@ -981,18 +981,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
let method_call = ty::MethodCall::expr(elt.id());
|
||||
let method_ty = self.infcx.node_method_ty(method_call);
|
||||
|
||||
let element_ty = match method_ty {
|
||||
let (element_ty, element_kind) = match method_ty {
|
||||
Some(method_ty) => {
|
||||
let ref_ty = self.overloaded_method_return_ty(method_ty);
|
||||
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
|
||||
|
||||
// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
|
||||
let self_ty = method_ty.fn_sig().input(0);
|
||||
self.tcx().no_late_bound_regions(&self_ty).unwrap()
|
||||
(self.tcx().no_late_bound_regions(&self_ty).unwrap(),
|
||||
ElementKind::OtherElement)
|
||||
}
|
||||
None => {
|
||||
match base_cmt.ty.builtin_index() {
|
||||
Some(ty) => ty,
|
||||
Some(ty) => (ty, ElementKind::VecElement),
|
||||
None => {
|
||||
return Err(());
|
||||
}
|
||||
|
|
@ -1000,102 +1001,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let m = base_cmt.mutbl.inherit();
|
||||
let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
|
||||
m, context, element_ty);
|
||||
let interior_elem = InteriorElement(context, element_kind);
|
||||
let ret =
|
||||
self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
|
||||
debug!("cat_index ret {:?}", ret);
|
||||
return Ok(ret);
|
||||
|
||||
fn interior<'tcx, N: ast_node>(elt: &N,
|
||||
of_cmt: cmt<'tcx>,
|
||||
vec_ty: Ty<'tcx>,
|
||||
mutbl: MutabilityCategory,
|
||||
context: InteriorOffsetKind,
|
||||
element_ty: Ty<'tcx>) -> cmt<'tcx>
|
||||
{
|
||||
let interior_elem = InteriorElement(context, element_kind(vec_ty));
|
||||
Rc::new(cmt_ {
|
||||
id:elt.id(),
|
||||
span:elt.span(),
|
||||
cat:Categorization::Interior(of_cmt, interior_elem),
|
||||
mutbl:mutbl,
|
||||
ty:element_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Takes either a vec or a reference to a vec and returns the cmt for the
|
||||
// underlying vec.
|
||||
fn deref_vec<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
context: InteriorOffsetKind)
|
||||
-> McResult<cmt<'tcx>>
|
||||
{
|
||||
let ret = match deref_kind(base_cmt.ty, Some(context))? {
|
||||
deref_ptr(ptr) => {
|
||||
// for unique ptrs, we inherit mutability from the
|
||||
// owning reference.
|
||||
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
|
||||
|
||||
// the deref is explicit in the resulting cmt
|
||||
Rc::new(cmt_ {
|
||||
id:elt.id(),
|
||||
span:elt.span(),
|
||||
cat:Categorization::Deref(base_cmt.clone(), 0, ptr),
|
||||
mutbl:m,
|
||||
ty: match base_cmt.ty.builtin_deref(false, ty::NoPreference) {
|
||||
Some(mt) => mt.ty,
|
||||
None => bug!("Found non-derefable type")
|
||||
},
|
||||
note: NoteNone
|
||||
})
|
||||
}
|
||||
|
||||
deref_interior(_) => {
|
||||
base_cmt
|
||||
}
|
||||
};
|
||||
debug!("deref_vec ret {:?}", ret);
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
|
||||
/// the pattern `Q`, returns:
|
||||
///
|
||||
/// * a cmt for `Q`
|
||||
/// * the mutability and region of the slice `Q`
|
||||
///
|
||||
/// These last two bits of info happen to be things that borrowck needs.
|
||||
pub fn cat_slice_pattern(&self,
|
||||
vec_cmt: cmt<'tcx>,
|
||||
slice_pat: &hir::Pat)
|
||||
-> McResult<(cmt<'tcx>, hir::Mutability, ty::Region)> {
|
||||
let slice_ty = self.node_ty(slice_pat.id)?;
|
||||
let (slice_mutbl, slice_r) = vec_slice_info(slice_pat, slice_ty);
|
||||
let context = InteriorOffsetKind::Pattern;
|
||||
let cmt_vec = self.deref_vec(slice_pat, vec_cmt, context)?;
|
||||
let cmt_slice = self.cat_index(slice_pat, cmt_vec, context)?;
|
||||
return Ok((cmt_slice, slice_mutbl, slice_r));
|
||||
|
||||
/// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
|
||||
/// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
|
||||
/// have to recurse through rptrs.
|
||||
fn vec_slice_info(pat: &hir::Pat, slice_ty: Ty)
|
||||
-> (hir::Mutability, ty::Region) {
|
||||
match slice_ty.sty {
|
||||
ty::TyRef(r, ref mt) => match mt.ty.sty {
|
||||
ty::TySlice(_) => (mt.mutbl, *r),
|
||||
_ => vec_slice_info(pat, mt.ty),
|
||||
},
|
||||
|
||||
_ => {
|
||||
span_bug!(pat.span,
|
||||
"type of slice pattern is not a slice");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_imm_interior<N:ast_node>(&self,
|
||||
|
|
@ -1319,15 +1229,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
|
||||
PatKind::Vec(ref before, ref slice, ref after) => {
|
||||
let context = InteriorOffsetKind::Pattern;
|
||||
let vec_cmt = self.deref_vec(pat, cmt, context)?;
|
||||
let elt_cmt = self.cat_index(pat, vec_cmt, context)?;
|
||||
let elt_cmt = self.cat_index(pat, cmt, context)?;
|
||||
for before_pat in before {
|
||||
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
|
||||
}
|
||||
if let Some(ref slice_pat) = *slice {
|
||||
let slice_ty = self.pat_ty(&slice_pat)?;
|
||||
let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
|
||||
self.cat_pattern_(slice_cmt, &slice_pat, op)?;
|
||||
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
|
||||
}
|
||||
for after_pat in after {
|
||||
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
|
||||
|
|
@ -1620,18 +1527,6 @@ impl fmt::Debug for InteriorKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn element_kind(t: Ty) -> ElementKind {
|
||||
match t.sty {
|
||||
ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
|
||||
ty::TyBox(ty) => match ty.sty {
|
||||
ty::TySlice(_) => VecElement,
|
||||
_ => OtherElement
|
||||
},
|
||||
ty::TyArray(..) | ty::TySlice(_) => VecElement,
|
||||
_ => OtherElement
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Upvar {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}/{:?}", self.id, self.kind)
|
||||
|
|
|
|||
|
|
@ -674,6 +674,14 @@ pub enum ProjectionElem<'tcx, V> {
|
|||
from_end: bool,
|
||||
},
|
||||
|
||||
/// These indices are generated by slice patterns.
|
||||
///
|
||||
/// slice[from:-to] in Python terms.
|
||||
Subslice {
|
||||
from: u32,
|
||||
to: u32,
|
||||
},
|
||||
|
||||
/// "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.
|
||||
|
|
@ -753,6 +761,14 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
|||
write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
|
||||
write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
|
||||
ProjectionElem::Subslice { from, to } if to == 0 =>
|
||||
write!(fmt, "{:?}[{:?}:", data.base, from),
|
||||
ProjectionElem::Subslice { from, to } if from == 0 =>
|
||||
write!(fmt, "{:?}[:-{:?}]", data.base, to),
|
||||
ProjectionElem::Subslice { from, to } =>
|
||||
write!(fmt, "{:?}[{:?}:-{:?}]", data.base,
|
||||
from, to),
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -856,17 +872,6 @@ pub enum Rvalue<'tcx> {
|
|||
/// away after type-checking and before lowering.
|
||||
Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
|
||||
|
||||
/// 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 {
|
||||
asm: InlineAsm,
|
||||
outputs: Vec<Lvalue<'tcx>>,
|
||||
|
|
@ -972,8 +977,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
|
||||
}
|
||||
Slice { ref input, from_start, from_end } =>
|
||||
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
|
||||
|
||||
Ref(_, borrow_kind, ref lv) => {
|
||||
let kind_str = match borrow_kind {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,20 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
|
|||
LvalueTy::Ty {
|
||||
ty: self.to_ty(tcx).builtin_index().unwrap()
|
||||
},
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
let ty = self.to_ty(tcx);
|
||||
LvalueTy::Ty {
|
||||
ty: match ty.sty {
|
||||
ty::TyArray(inner, size) => {
|
||||
tcx.mk_array(inner, size-(from as usize)-(to as usize))
|
||||
}
|
||||
ty::TySlice(..) => ty,
|
||||
_ => {
|
||||
bug!("cannot subslice non-array type: `{:?}`", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Downcast(adt_def1, index) =>
|
||||
match self.to_ty(tcx).sty {
|
||||
ty::TyEnum(adt_def, substs) => {
|
||||
|
|
@ -219,7 +233,6 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Slice { .. } => None,
|
||||
Rvalue::InlineAsm { .. } => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
286
src/librustc/mir/traversal.rs
Normal file
286
src/librustc/mir/traversal.rs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// Copyright 2016 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::vec;
|
||||
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
|
||||
use super::repr::*;
|
||||
|
||||
/// Preorder traversal of a graph.
|
||||
///
|
||||
/// Preorder traversal is when each node is visited before an of it's
|
||||
/// successors
|
||||
///
|
||||
/// ```text
|
||||
///
|
||||
/// A
|
||||
/// / \
|
||||
/// / \
|
||||
/// B C
|
||||
/// \ /
|
||||
/// \ /
|
||||
/// D
|
||||
/// ```
|
||||
///
|
||||
/// A preorder traversal of this graph is either `A B D C` or `A C D B`
|
||||
#[derive(Clone)]
|
||||
pub struct Preorder<'a, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
visited: BitVector,
|
||||
worklist: Vec<BasicBlock>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Preorder<'a, 'tcx> {
|
||||
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
|
||||
let worklist = vec![root];
|
||||
|
||||
Preorder {
|
||||
mir: mir,
|
||||
visited: BitVector::new(mir.basic_blocks.len()),
|
||||
worklist: worklist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preorder<'a, 'tcx>(mir: &'a Mir<'tcx>) -> Preorder<'a, 'tcx> {
|
||||
Preorder::new(mir, START_BLOCK)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
|
||||
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
|
||||
|
||||
fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
|
||||
while let Some(idx) = self.worklist.pop() {
|
||||
if !self.visited.insert(idx.index()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let data = self.mir.basic_block_data(idx);
|
||||
|
||||
if let Some(ref term) = data.terminator {
|
||||
for &succ in term.successors().iter() {
|
||||
self.worklist.push(succ);
|
||||
}
|
||||
}
|
||||
|
||||
return Some((idx, data));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Postorder traversal of a graph.
|
||||
///
|
||||
/// Postorder traversal is when each node is visited after all of it's
|
||||
/// successors, except when the successor is only reachable by a back-edge
|
||||
///
|
||||
///
|
||||
/// ```text
|
||||
///
|
||||
/// A
|
||||
/// / \
|
||||
/// / \
|
||||
/// B C
|
||||
/// \ /
|
||||
/// \ /
|
||||
/// D
|
||||
/// ```
|
||||
///
|
||||
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
|
||||
pub struct Postorder<'a, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
visited: BitVector,
|
||||
visit_stack: Vec<(BasicBlock, vec::IntoIter<BasicBlock>)>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Postorder<'a, 'tcx> {
|
||||
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
|
||||
let mut po = Postorder {
|
||||
mir: mir,
|
||||
visited: BitVector::new(mir.basic_blocks.len()),
|
||||
visit_stack: Vec::new()
|
||||
};
|
||||
|
||||
|
||||
let data = po.mir.basic_block_data(root);
|
||||
|
||||
if let Some(ref term) = data.terminator {
|
||||
po.visited.insert(root.index());
|
||||
|
||||
let succs = term.successors().into_owned().into_iter();
|
||||
|
||||
po.visit_stack.push((root, succs));
|
||||
po.traverse_successor();
|
||||
}
|
||||
|
||||
po
|
||||
}
|
||||
|
||||
fn traverse_successor(&mut self) {
|
||||
// This is quite a complex loop due to 1. the borrow checker not liking it much
|
||||
// and 2. what exactly is going on is not clear
|
||||
//
|
||||
// It does the actual traversal of the graph, while the `next` method on the iterator
|
||||
// just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and
|
||||
// iterators over the sucessors of those nodes. Each iteration attempts to get the next
|
||||
// node from the top of the stack, then pushes that node and an iterator over the
|
||||
// successors to the top of the stack. This loop only grows `visit_stack`, stopping when
|
||||
// we reach a child that has no children that we haven't already visited.
|
||||
//
|
||||
// For a graph that looks like this:
|
||||
//
|
||||
// A
|
||||
// / \
|
||||
// / \
|
||||
// B C
|
||||
// | |
|
||||
// | |
|
||||
// D |
|
||||
// \ /
|
||||
// \ /
|
||||
// E
|
||||
//
|
||||
// The state of the stack starts out with just the root node (`A` in this case);
|
||||
// [(A, [B, C])]
|
||||
//
|
||||
// When the first call to `traverse_sucessor` happens, the following happens:
|
||||
//
|
||||
// [(B, [D]), // `B` taken from the successors of `A`, pushed to the
|
||||
// // top of the stack along with the successors of `B`
|
||||
// (A, [C])]
|
||||
//
|
||||
// [(D, [E]), // `D` taken from successors of `B`, pushed to stack
|
||||
// (B, []),
|
||||
// (A, [C])]
|
||||
//
|
||||
// [(E, []), // `E` taken from successors of `D`, pushed to stack
|
||||
// (D, []),
|
||||
// (B, []),
|
||||
// (A, [C])]
|
||||
//
|
||||
// Now that the top of the stack has no successors we can traverse, each item will
|
||||
// be popped off during iteration until we get back to `A`. This yeilds [E, D, B].
|
||||
//
|
||||
// When we yield `B` and call `traverse_successor`, we push `C` to the stack, but
|
||||
// since we've already visited `E`, that child isn't added to the stack. The last
|
||||
// two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
|
||||
loop {
|
||||
let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
|
||||
if let Some(bb) = iter.next() {
|
||||
bb
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
|
||||
if self.visited.insert(bb.index()) {
|
||||
let data = self.mir.basic_block_data(bb);
|
||||
|
||||
if let Some(ref term) = data.terminator {
|
||||
let succs = term.successors().into_owned().into_iter();
|
||||
self.visit_stack.push((bb, succs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn postorder<'a, 'tcx>(mir: &'a Mir<'tcx>) -> Postorder<'a, 'tcx> {
|
||||
Postorder::new(mir, START_BLOCK)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
|
||||
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
|
||||
|
||||
fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
|
||||
let next = self.visit_stack.pop();
|
||||
if next.is_some() {
|
||||
self.traverse_successor();
|
||||
}
|
||||
|
||||
next.map(|(bb, _)| {
|
||||
let data = self.mir.basic_block_data(bb);
|
||||
(bb, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Reverse postorder traversal of a graph
|
||||
///
|
||||
/// Reverse postorder is the reverse order of a postorder traversal.
|
||||
/// This is different to a preorder traversal and represents a natural
|
||||
/// linearisation of control-flow.
|
||||
///
|
||||
/// ```text
|
||||
///
|
||||
/// A
|
||||
/// / \
|
||||
/// / \
|
||||
/// B C
|
||||
/// \ /
|
||||
/// \ /
|
||||
/// D
|
||||
/// ```
|
||||
///
|
||||
/// A reverse postorder traversal of this graph is either `A B C D` or `A C B D`
|
||||
/// Note that for a graph containing no loops (i.e. A DAG), this is equivalent to
|
||||
/// a topological sort.
|
||||
///
|
||||
/// Construction of a `ReversePostorder` traversal requires doing a full
|
||||
/// postorder traversal of the graph, therefore this traversal should be
|
||||
/// constructed as few times as possible. Use the `reset` method to be able
|
||||
/// to re-use the traversal
|
||||
#[derive(Clone)]
|
||||
pub struct ReversePostorder<'a, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
blocks: Vec<BasicBlock>,
|
||||
idx: usize
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
|
||||
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
|
||||
let blocks : Vec<_> = Postorder::new(mir, root).map(|(bb, _)| bb).collect();
|
||||
|
||||
let len = blocks.len();
|
||||
|
||||
ReversePostorder {
|
||||
mir: mir,
|
||||
blocks: blocks,
|
||||
idx: len
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.idx = self.blocks.len();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn reverse_postorder<'a, 'tcx>(mir: &'a Mir<'tcx>) -> ReversePostorder<'a, 'tcx> {
|
||||
ReversePostorder::new(mir, START_BLOCK)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
|
||||
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
|
||||
|
||||
fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
|
||||
if self.idx == 0 { return None; }
|
||||
self.idx -= 1;
|
||||
|
||||
self.blocks.get(self.idx).map(|&bb| {
|
||||
let data = self.mir.basic_block_data(bb);
|
||||
(bb, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -533,15 +533,6 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::Slice { ref $($mutability)* input,
|
||||
from_start,
|
||||
from_end } => {
|
||||
self.visit_lvalue(input, LvalueContext::Slice {
|
||||
from_start: from_start,
|
||||
from_end: from_end,
|
||||
});
|
||||
}
|
||||
|
||||
Rvalue::InlineAsm { ref $($mutability)* outputs,
|
||||
ref $($mutability)* inputs,
|
||||
asm: _ } => {
|
||||
|
|
@ -602,6 +593,8 @@ macro_rules! make_mir_visitor {
|
|||
match *proj {
|
||||
ProjectionElem::Deref => {
|
||||
}
|
||||
ProjectionElem::Subslice { from: _, to: _ } => {
|
||||
}
|
||||
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ use session::Session;
|
|||
use traits;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use util::common::slice_pat;
|
||||
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
|
@ -98,17 +100,17 @@ impl TargetDataLayout {
|
|||
|
||||
let mut dl = TargetDataLayout::default();
|
||||
for spec in sess.target.target.data_layout.split("-") {
|
||||
match &spec.split(":").collect::<Vec<_>>()[..] {
|
||||
["e"] => dl.endian = Endian::Little,
|
||||
["E"] => dl.endian = Endian::Big,
|
||||
["a", a..] => dl.aggregate_align = align(a, "a"),
|
||||
["f32", a..] => dl.f32_align = align(a, "f32"),
|
||||
["f64", a..] => dl.f64_align = align(a, "f64"),
|
||||
[p @ "p", s, a..] | [p @ "p0", s, a..] => {
|
||||
match slice_pat(&&spec.split(":").collect::<Vec<_>>()[..]) {
|
||||
&["e"] => dl.endian = Endian::Little,
|
||||
&["E"] => dl.endian = Endian::Big,
|
||||
&["a", ref a..] => dl.aggregate_align = align(a, "a"),
|
||||
&["f32", ref a..] => dl.f32_align = align(a, "f32"),
|
||||
&["f64", ref a..] => dl.f64_align = align(a, "f64"),
|
||||
&[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => {
|
||||
dl.pointer_size = size(s, p);
|
||||
dl.pointer_align = align(a, p);
|
||||
}
|
||||
[s, a..] if s.starts_with("i") => {
|
||||
&[s, ref a..] if s.starts_with("i") => {
|
||||
let ty_align = match s[1..].parse::<u64>() {
|
||||
Ok(1) => &mut dl.i8_align,
|
||||
Ok(8) => &mut dl.i8_align,
|
||||
|
|
@ -123,7 +125,7 @@ impl TargetDataLayout {
|
|||
};
|
||||
*ty_align = align(a, s);
|
||||
}
|
||||
[s, a..] if s.starts_with("v") => {
|
||||
&[s, ref a..] if s.starts_with("v") => {
|
||||
let v_size = size(&s[1..], "v");
|
||||
let a = align(a, s);
|
||||
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
|
||||
|
|
|
|||
|
|
@ -247,3 +247,15 @@ pub fn path2cstr(p: &Path) -> CString {
|
|||
pub fn path2cstr(p: &Path) -> CString {
|
||||
CString::new(p.to_str().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
// FIXME(stage0): remove this
|
||||
// HACK: this is needed because the interpretation of slice
|
||||
// patterns changed between stage0 and now.
|
||||
#[cfg(stage0)]
|
||||
pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
|
||||
t
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
|
||||
*t
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue