Skip to content

Commit

Permalink
Auto merge of #32156 - pnkfelix:borrowck-on-mir-move-analysis, r=niko…
Browse files Browse the repository at this point in the history
…matsakis

Move analysis for MIR borrowck

This PR adds code for doing MIR-based gathering of the moves in a `fn` and the dataflow to determine where uninitialized locations flow to, analogous to how the same thing is done in `borrowck`.

It also adds a couple attributes to print out graphviz visualizations of the analyzed MIR that includes the dataflow analysis results.

cc @nikomatsakis
  • Loading branch information
bors committed Mar 22, 2016
2 parents c7bdfd4 + 782c0cf commit e3f2dfd
Show file tree
Hide file tree
Showing 34 changed files with 2,014 additions and 136 deletions.
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
log graphviz rustc_llvm rustc_back rustc_data_structures\
rustc_const_eval
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
DEPS_rustc_borrowck := rustc rustc_front rustc_mir log graphviz syntax
DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
Expand Down
102 changes: 63 additions & 39 deletions src/libgraphviz/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,19 @@
//! dot::render(&edges, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd, Ed> for Edges {
//! impl<'a> dot::Labeller<'a> for Edges {
//! type Node = Nd;
//! type Edge = Ed;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example1").unwrap() }
//!
//! fn node_id(&'a self, n: &Nd) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", *n)).unwrap()
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd, Ed> for Edges {
//! impl<'a> dot::GraphWalk<'a> for Edges {
//! type Node = Nd;
//! type Edge = Ed;
//! fn nodes(&self) -> dot::Nodes<'a,Nd> {
//! // (assumes that |N| \approxeq |E|)
//! let &Edges(ref v) = self;
Expand Down Expand Up @@ -167,7 +171,9 @@
//! dot::render(&graph, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph {
//! impl<'a> dot::Labeller<'a> for Graph {
//! type Node = Nd;
//! type Edge = Ed<'a>;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example2").unwrap() }
//! fn node_id(&'a self, n: &Nd) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", n)).unwrap()
Expand All @@ -180,7 +186,9 @@
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph {
//! impl<'a> dot::GraphWalk<'a> for Graph {
//! type Node = Nd;
//! type Edge = Ed<'a>;
//! fn nodes(&self) -> dot::Nodes<'a,Nd> { (0..self.nodes.len()).collect() }
//! fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { self.edges.iter().collect() }
//! fn source(&self, e: &Ed) -> Nd { let & &(s,_) = e; s }
Expand Down Expand Up @@ -225,7 +233,9 @@
//! dot::render(&graph, output).unwrap()
//! }
//!
//! impl<'a> dot::Labeller<'a, Nd<'a>, Ed<'a>> for Graph {
//! impl<'a> dot::Labeller<'a> for Graph {
//! type Node = Nd<'a>;
//! type Edge = Ed<'a>;
//! fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3").unwrap() }
//! fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", n.0)).unwrap()
Expand All @@ -239,7 +249,9 @@
//! }
//! }
//!
//! impl<'a> dot::GraphWalk<'a, Nd<'a>, Ed<'a>> for Graph {
//! impl<'a> dot::GraphWalk<'a> for Graph {
//! type Node = Nd<'a>;
//! type Edge = Ed<'a>;
//! fn nodes(&'a self) -> dot::Nodes<'a,Nd<'a>> {
//! self.nodes.iter().map(|s| &s[..]).enumerate().collect()
//! }
Expand Down Expand Up @@ -447,45 +459,48 @@ impl<'a> Id<'a> {
/// The graph instance is responsible for providing the DOT compatible
/// identifiers for the nodes and (optionally) rendered labels for the nodes and
/// edges, as well as an identifier for the graph itself.
pub trait Labeller<'a,N,E> {
pub trait Labeller<'a> {
type Node;
type Edge;

/// Must return a DOT compatible identifier naming the graph.
fn graph_id(&'a self) -> Id<'a>;

/// Maps `n` to a unique identifier with respect to `self`. The
/// implementor is responsible for ensuring that the returned name
/// is a valid DOT identifier.
fn node_id(&'a self, n: &N) -> Id<'a>;
fn node_id(&'a self, n: &Self::Node) -> Id<'a>;

/// Maps `n` to one of the [graphviz `shape` names][1]. If `None`
/// is returned, no `shape` attribute is specified.
///
/// [1]: http://www.graphviz.org/content/node-shapes
fn node_shape(&'a self, _node: &N) -> Option<LabelText<'a>> {
fn node_shape(&'a self, _node: &Self::Node) -> Option<LabelText<'a>> {
None
}

/// Maps `n` to a label that will be used in the rendered output.
/// The label need not be unique, and may be the empty string; the
/// default is just the output from `node_id`.
fn node_label(&'a self, n: &N) -> LabelText<'a> {
fn node_label(&'a self, n: &Self::Node) -> LabelText<'a> {
LabelStr(self.node_id(n).name)
}

/// Maps `e` to a label that will be used in the rendered output.
/// The label need not be unique, and may be the empty string; the
/// default is in fact the empty string.
fn edge_label(&'a self, e: &E) -> LabelText<'a> {
fn edge_label(&'a self, e: &Self::Edge) -> LabelText<'a> {
let _ignored = e;
LabelStr("".into_cow())
}

/// Maps `n` to a style that will be used in the rendered output.
fn node_style(&'a self, _n: &N) -> Style {
fn node_style(&'a self, _n: &Self::Node) -> Style {
Style::None
}

/// Maps `e` to a style that will be used in the rendered output.
fn edge_style(&'a self, _e: &E) -> Style {
fn edge_style(&'a self, _e: &Self::Edge) -> Style {
Style::None
}
}
Expand Down Expand Up @@ -596,15 +611,18 @@ pub type Edges<'a,E> = Cow<'a,[E]>;
/// `Cow<[T]>` to leave implementors the freedom to create
/// entirely new vectors or to pass back slices into internally owned
/// vectors.
pub trait GraphWalk<'a, N: Clone, E: Clone> {
pub trait GraphWalk<'a> {
type Node: Clone;
type Edge: Clone;

/// Returns all the nodes in this graph.
fn nodes(&'a self) -> Nodes<'a, N>;
fn nodes(&'a self) -> Nodes<'a, Self::Node>;
/// Returns all of the edges in this graph.
fn edges(&'a self) -> Edges<'a, E>;
fn edges(&'a self) -> Edges<'a, Self::Edge>;
/// The source node for `edge`.
fn source(&'a self, edge: &E) -> N;
fn source(&'a self, edge: &Self::Edge) -> Self::Node;
/// The target node for `edge`.
fn target(&'a self, edge: &E) -> N;
fn target(&'a self, edge: &Self::Edge) -> Self::Node;
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
Expand All @@ -622,28 +640,26 @@ pub fn default_options() -> Vec<RenderOption> {

/// Renders directed graph `g` into the writer `w` in DOT syntax.
/// (Simple wrapper around `render_opts` that passes a default set of options.)
pub fn render<'a,
N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, N, E> + GraphWalk<'a, N, E>,
W: Write>
(g: &'a G,
w: &mut W)
-> io::Result<()> {
pub fn render<'a,N,E,G,W>(g: &'a G, w: &mut W) -> io::Result<()>
where N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, Node=N, Edge=E> + GraphWalk<'a, Node=N, Edge=E>,
W: Write
{
render_opts(g, w, &[])
}

/// Renders directed graph `g` into the writer `w` in DOT syntax.
/// (Main entry point for the library.)
pub fn render_opts<'a,
N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, N, E> + GraphWalk<'a, N, E>,
W: Write>
(g: &'a G,
w: &mut W,
options: &[RenderOption])
-> io::Result<()> {
pub fn render_opts<'a, N, E, G, W>(g: &'a G,
w: &mut W,
options: &[RenderOption])
-> io::Result<()>
where N: Clone + 'a,
E: Clone + 'a,
G: Labeller<'a, Node=N, Edge=E> + GraphWalk<'a, Node=N, Edge=E>,
W: Write
{
fn writeln<W: Write>(w: &mut W, arg: &[&str]) -> io::Result<()> {
for &s in arg {
try!(w.write_all(s.as_bytes()));
Expand Down Expand Up @@ -858,7 +874,9 @@ mod tests {
Id::new(format!("N{}", *n)).unwrap()
}

impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraph {
impl<'a> Labeller<'a> for LabelledGraph {
type Node = Node;
type Edge = &'a Edge;
fn graph_id(&'a self) -> Id<'a> {
Id::new(&self.name[..]).unwrap()
}
Expand All @@ -882,7 +900,9 @@ mod tests {
}
}

impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraphWithEscStrs {
impl<'a> Labeller<'a> for LabelledGraphWithEscStrs {
type Node = Node;
type Edge = &'a Edge;
fn graph_id(&'a self) -> Id<'a> {
self.graph.graph_id()
}
Expand All @@ -901,7 +921,9 @@ mod tests {
}
}

impl<'a> GraphWalk<'a, Node, &'a Edge> for LabelledGraph {
impl<'a> GraphWalk<'a> for LabelledGraph {
type Node = Node;
type Edge = &'a Edge;
fn nodes(&'a self) -> Nodes<'a, Node> {
(0..self.node_labels.len()).collect()
}
Expand All @@ -916,7 +938,9 @@ mod tests {
}
}

impl<'a> GraphWalk<'a, Node, &'a Edge> for LabelledGraphWithEscStrs {
impl<'a> GraphWalk<'a> for LabelledGraphWithEscStrs {
type Node = Node;
type Edge = &'a Edge;
fn nodes(&'a self) -> Nodes<'a, Node> {
self.graph.nodes()
}
Expand Down
47 changes: 28 additions & 19 deletions src/librustc/front/map/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ pub use self::Code::*;
use front::map::{self, Node};
use syntax::abi;
use rustc_front::hir::{Block, FnDecl};
use syntax::ast::{Name, NodeId};
use syntax::ast::{Attribute, Name, NodeId};
use syntax::attr::ThinAttributesExt;
use rustc_front::hir as ast;
use syntax::codemap::Span;
use rustc_front::intravisit::FnKind;
Expand Down Expand Up @@ -116,7 +117,8 @@ struct ItemFnParts<'a> {
generics: &'a ast::Generics,
body: &'a Block,
id: NodeId,
span: Span
span: Span,
attrs: &'a [Attribute],
}

/// These are all the components one can extract from a closure expr
Expand All @@ -125,12 +127,13 @@ struct ClosureParts<'a> {
decl: &'a FnDecl,
body: &'a Block,
id: NodeId,
span: Span
span: Span,
attrs: &'a [Attribute],
}

impl<'a> ClosureParts<'a> {
fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
ClosureParts { decl: d, body: b, id: id, span: s }
fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
ClosureParts { decl: d, body: b, id: id, span: s, attrs: attrs }
}
}

Expand Down Expand Up @@ -165,37 +168,37 @@ impl<'a> FnLikeNode<'a> {

pub fn body(self) -> &'a Block {
self.handle(|i: ItemFnParts<'a>| &*i.body,
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body,
|c: ClosureParts<'a>| c.body)
}

pub fn decl(self) -> &'a FnDecl {
self.handle(|i: ItemFnParts<'a>| &*i.decl,
|_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
|_, _, sig: &'a ast::MethodSig, _, _, _, _| &sig.decl,
|c: ClosureParts<'a>| c.decl)
}

pub fn span(self) -> Span {
self.handle(|i: ItemFnParts| i.span,
|_, _, _: &'a ast::MethodSig, _, _, span| span,
|_, _, _: &'a ast::MethodSig, _, _, span, _| span,
|c: ClosureParts| c.span)
}

pub fn id(self) -> NodeId {
self.handle(|i: ItemFnParts| i.id,
|id, _, _: &'a ast::MethodSig, _, _, _| id,
|id, _, _: &'a ast::MethodSig, _, _, _, _| id,
|c: ClosureParts| c.id)
}

pub fn kind(self) -> FnKind<'a> {
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis)
FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
};
let closure = |_: ClosureParts| {
FnKind::Closure
let closure = |c: ClosureParts<'a>| {
FnKind::Closure(c.attrs)
};
let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _| {
FnKind::Method(name, sig, vis)
let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _, attrs| {
FnKind::Method(name, sig, vis, attrs)
};
self.handle(item, method, closure)
}
Expand All @@ -207,7 +210,8 @@ impl<'a> FnLikeNode<'a> {
&'a ast::MethodSig,
Option<ast::Visibility>,
&'a ast::Block,
Span)
Span,
&'a [Attribute])
-> A,
C: FnOnce(ClosureParts<'a>) -> A,
{
Expand All @@ -224,20 +228,21 @@ impl<'a> FnLikeNode<'a> {
abi: abi,
vis: i.vis,
constness: constness,
span: i.span
span: i.span,
attrs: &i.attrs,
}),
_ => panic!("item FnLikeNode that is not fn-like"),
},
map::NodeTraitItem(ti) => match ti.node {
ast::MethodTraitItem(ref sig, Some(ref body)) => {
method(ti.id, ti.name, sig, None, body, ti.span)
method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
}
_ => panic!("trait method FnLikeNode that is not fn-like"),
},
map::NodeImplItem(ii) => {
match ii.node {
ast::ImplItemKind::Method(ref sig, ref body) => {
method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span)
method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span, &ii.attrs)
}
_ => {
panic!("impl method FnLikeNode that is not fn-like")
Expand All @@ -246,7 +251,11 @@ impl<'a> FnLikeNode<'a> {
}
map::NodeExpr(e) => match e.node {
ast::ExprClosure(_, ref decl, ref block) =>
closure(ClosureParts::new(&decl, &block, e.id, e.span)),
closure(ClosureParts::new(&decl,
&block,
e.id,
e.span,
e.attrs.as_attr_slice())),
_ => panic!("expr FnLikeNode that is not fn-like"),
},
_ => panic!("other FnLikeNode that is not fn-like"),
Expand Down
Loading

0 comments on commit e3f2dfd

Please sign in to comment.