Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

construct MIR for all crates up to and including rustdoc #27893

Merged
merged 12 commits into from Sep 6, 2015
Merged
5 changes: 3 additions & 2 deletions mk/crates.mk
Expand Up @@ -54,7 +54,7 @@ TARGET_CRATES := libc std flate arena term \
log graphviz core rbml alloc \
rustc_unicode rustc_bitflags \
alloc_system
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures rustc_front rustc_platform_intrinsics
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
Expand All @@ -70,11 +70,12 @@ DEPS_std := core libc rand alloc collections rustc_unicode \
DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_resolve log syntax serialize rustc_llvm \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_front

DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
DEPS_rustc_mir := rustc rustc_front syntax
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
DEPS_rustc_resolve := rustc rustc_front log syntax
Expand Down
12 changes: 12 additions & 0 deletions mk/main.mk
Expand Up @@ -172,6 +172,18 @@ RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
# by not emitting them.
RUSTFLAGS_STAGE0 += -Z no-landing-pads

# Enable MIR to "always build" for crates where this works. This is
# just temporary while MIR is being actively built up -- it's just a
# poor man's unit testing infrastructure. Anyway we only want this for
# stage1/stage2.
define ADD_MIR_FLAG
RUSTFLAGS1_$(1) += -Z always-build-mir
RUSTFLAGS2_$(1) += -Z always-build-mir
endef
$(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
$(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))

# platform-specific auto-configuration
include $(CFG_SRC_DIR)mk/platform.mk

Expand Down
1 change: 1 addition & 0 deletions mk/target.mk
Expand Up @@ -93,6 +93,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(LLVM_STDCPP_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4)) \
$$(RUSTFLAGS$(1)_$(4)) \
$$(RUSTFLAGS$(1)_$(4)_T_$(2)) \
--out-dir $$(@D) \
-C extra-filename=-$$(CFG_FILENAME_EXTRA) \
Expand Down
64 changes: 52 additions & 12 deletions src/libgraphviz/lib.rs
Expand Up @@ -313,6 +313,13 @@ pub enum LabelText<'a> {
/// are also the escape sequences `\l` which left-justifies the
/// preceding line and `\r` which right-justifies it.
EscStr(Cow<'a, str>),

/// This uses a graphviz [HTML string label][html]. The string is
/// printed exactly as given, but between `<` and `>`. **No
/// escaping is performed.**
///
/// [html]: http://www.graphviz.org/content/node-shapes#html
HtmlStr(Cow<'a, str>),
}

/// The style for a node or edge.
Expand Down Expand Up @@ -453,6 +460,14 @@ pub trait Labeller<'a,N,E> {
/// is a valid DOT identifier.
fn node_id(&'a self, n: &N) -> 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>> {
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`.
Expand All @@ -479,6 +494,16 @@ pub trait Labeller<'a,N,E> {
}
}

/// Escape tags in such a way that it is suitable for inclusion in a
/// Graphviz HTML label.
pub fn escape_html(s: &str) -> String {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... this isn't a great escape function, but I guess it's not really untrusted input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, yes. :)

s
.replace("&", "&amp;")
.replace("\"", "&quot;")
.replace("<", "&lt;")
.replace(">", "&gt;")
}

impl<'a> LabelText<'a> {
pub fn label<S:IntoCow<'a, str>>(s: S) -> LabelText<'a> {
LabelStr(s.into_cow())
Expand All @@ -488,6 +513,10 @@ impl<'a> LabelText<'a> {
EscStr(s.into_cow())
}

pub fn html<S:IntoCow<'a, str>>(s: S) -> LabelText<'a> {
HtmlStr(s.into_cow())
}

fn escape_char<F>(c: char, mut f: F) where F: FnMut(char) {
match c {
// not escaping \\, since Graphviz escString needs to
Expand All @@ -505,10 +534,12 @@ impl<'a> LabelText<'a> {
}

/// Renders text as string suitable for a label in a .dot file.
pub fn escape(&self) -> String {
/// This includes quotes or suitable delimeters.
pub fn to_dot_string(&self) -> String {
match self {
&LabelStr(ref s) => s.escape_default(),
&EscStr(ref s) => LabelText::escape_str(&s[..]),
&LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
&EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s[..])),
&HtmlStr(ref s) => format!("<{}>", s),
}
}

Expand All @@ -524,6 +555,7 @@ impl<'a> LabelText<'a> {
} else {
s
},
HtmlStr(s) => s,
}
}

Expand Down Expand Up @@ -612,14 +644,15 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N
try!(indent(w));
let id = g.node_id(n);

let escaped = &g.node_label(n).escape();
let escaped = &g.node_label(n).to_dot_string();
let shape;

let mut text = vec![id.as_slice()];

if !options.contains(&RenderOption::NoNodeLabels) {
text.push("[label=\"");
text.push("[label=");
text.push(escaped);
text.push("\"]");
text.push("]");
}

let style = g.node_style(n);
Expand All @@ -629,12 +662,19 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N
text.push("\"]");
}

if let Some(s) = g.node_shape(n) {
shape = s.to_dot_string();
text.push("[shape=");
text.push(&shape);
text.push("]");
}

text.push(";");
try!(writeln(w, &text));
}

for e in g.edges().iter() {
let escaped_label = &g.edge_label(e).escape();
let escaped_label = &g.edge_label(e).to_dot_string();
try!(indent(w));
let source = g.source(e);
let target = g.target(e);
Expand All @@ -644,9 +684,9 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N
let mut text = vec![source_id.as_slice(), " -> ", target_id.as_slice()];

if !options.contains(&RenderOption::NoEdgeLabels) {
text.push("[label=\"");
text.push("[label=");
text.push(escaped_label);
text.push("\"]");
text.push("]");
}

let style = g.edge_style(e);
Expand All @@ -667,7 +707,7 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N
mod tests {
use self::NodeLabels::*;
use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style};
use super::LabelText::{self, LabelStr, EscStr};
use super::LabelText::{self, LabelStr, EscStr, HtmlStr};
use std::io;
use std::io::prelude::*;
use std::borrow::IntoCow;
Expand Down Expand Up @@ -805,12 +845,12 @@ mod tests {
fn node_id(&'a self, n: &Node) -> Id<'a> { self.graph.node_id(n) }
fn node_label(&'a self, n: &Node) -> LabelText<'a> {
match self.graph.node_label(n) {
LabelStr(s) | EscStr(s) => EscStr(s),
LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
}
}
fn edge_label(&'a self, e: & &'a Edge) -> LabelText<'a> {
match self.graph.edge_label(e) {
LabelStr(s) | EscStr(s) => EscStr(s),
LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/astencode.rs
Expand Up @@ -470,8 +470,8 @@ impl tr for def::Def {
def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
def::DefUse(did) => def::DefUse(did.tr(dcx)),
def::DefUpvar(nid1, nid2) => {
def::DefUpvar(dcx.tr_id(nid1), dcx.tr_id(nid2))
def::DefUpvar(nid1, index, nid2) => {
def::DefUpvar(dcx.tr_id(nid1), index, dcx.tr_id(nid2))
}
def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)),
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/def.rs
Expand Up @@ -38,6 +38,7 @@ pub enum Def {
DefTyParam(ParamSpace, u32, DefId, ast::Name),
DefUse(DefId),
DefUpvar(ast::NodeId, // id of closed over local
usize, // index in the freevars list of the closure
ast::NodeId), // expr node that creates the closure

/// Note that if it's a tuple struct's definition, the node id of the DefId
Expand Down Expand Up @@ -129,7 +130,7 @@ impl Def {
id
}
DefLocal(id) |
DefUpvar(id, _) |
DefUpvar(id, _, _) |
DefRegion(id) |
DefLabel(id) |
DefSelfTy(_, Some((_, id))) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Expand Up @@ -246,7 +246,7 @@ impl OverloadedCallType {
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d+'t> {
typer: &'t infer::InferCtxt<'a, 'tcx>,
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
delegate: &'d mut (Delegate<'tcx>+'d),
delegate: &'d mut Delegate<'tcx>,
}

// If the TYPER results in an error, it's because the type check
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -578,7 +578,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
}))
}

def::DefUpvar(var_id, fn_node_id) => {
def::DefUpvar(var_id, _, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
ty::TyClosure(closure_id, _) => {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/region.rs
Expand Up @@ -329,6 +329,9 @@ impl RegionMaps {
pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent {
self.lookup_code_extent(CodeExtentData::DestructionScope(n))
}
pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
self.code_extent_interner.borrow().get(&CodeExtentData::DestructionScope(n)).cloned()
}
pub fn intern_code_extent(&self,
e: CodeExtentData,
parent: CodeExtent) -> CodeExtent {
Expand Down
65 changes: 43 additions & 22 deletions src/librustc/middle/ty.rs
Expand Up @@ -3475,6 +3475,13 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
.expect("variant_with_id: unknown variant")
}

pub fn variant_index_with_id(&self, vid: DefId) -> usize {
self.variants
.iter()
.position(|v| v.did == vid)
.expect("variant_index_with_id: unknown variant")
}

pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> {
match def {
def::DefVariant(_, vid, _) => self.variant_with_id(vid),
Expand Down Expand Up @@ -5191,28 +5198,12 @@ impl<'tcx> TyS<'tcx> {

if !adjusted_ty.references_error() {
for i in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(expr_id, i as u32);
match method_type(method_call) {
Some(method_ty) => {
// Overloaded deref operators have all late-bound
// regions fully instantiated and coverge.
let fn_ret =
cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
adjusted_ty = fn_ret.unwrap();
}
None => {}
}
match adjusted_ty.builtin_deref(true, NoPreference) {
Some(mt) => { adjusted_ty = mt.ty; }
None => {
cx.sess.span_bug(
span,
&format!("the {}th autoderef failed: {}",
i,
adjusted_ty)
);
}
}
adjusted_ty =
adjusted_ty.adjust_for_autoderef(cx,
expr_id,
span,
i as u32,
&mut method_type);
}
}

Expand All @@ -5228,6 +5219,36 @@ impl<'tcx> TyS<'tcx> {
};
}

pub fn adjust_for_autoderef<F>(&'tcx self,
cx: &ctxt<'tcx>,
expr_id: ast::NodeId,
expr_span: Span,
autoderef: u32, // how many autoderefs so far?
mut method_type: F)
-> Ty<'tcx> where
F: FnMut(MethodCall) -> Option<Ty<'tcx>>,
{
let method_call = MethodCall::autoderef(expr_id, autoderef);
let mut adjusted_ty = self;
if let Some(method_ty) = method_type(method_call) {
// Method calls always have all late-bound regions
// fully instantiated.
let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
adjusted_ty = fn_ret.unwrap();
}
match adjusted_ty.builtin_deref(true, NoPreference) {
Some(mt) => mt.ty,
None => {
cx.sess.span_bug(
expr_span,
&format!("the {}th autoderef failed: {}",
autoderef,
adjusted_ty)
);
}
}
}

pub fn adjust_for_autoref(&'tcx self, cx: &ctxt<'tcx>,
autoref: Option<AutoRef<'tcx>>)
-> Ty<'tcx> {
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/session/config.rs
Expand Up @@ -104,6 +104,7 @@ pub struct Options {
pub parse_only: bool,
pub no_trans: bool,
pub treat_err_as_bug: bool,
pub always_build_mir: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
/// Whether to write dependency files. It's (enabled, optional filename).
Expand Down Expand Up @@ -216,6 +217,7 @@ pub fn basic_options() -> Options {
parse_only: false,
no_trans: false,
treat_err_as_bug: false,
always_build_mir: false,
no_analysis: false,
debugging_opts: basic_debugging_options(),
write_dependency_info: (false, None),
Expand Down Expand Up @@ -583,6 +585,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"Run all passes except translation; no output"),
treat_err_as_bug: bool = (false, parse_bool,
"Treat all errors that occur as bugs"),
always_build_mir: bool = (false, parse_bool,
"Always build MIR for all fns, even without a #[rustc_mir] annotation"),
no_analysis: bool = (false, parse_bool,
"Parse and expand the source, but run no analysis"),
extra_plugins: Vec<String> = (Vec::new(), parse_list,
Expand Down Expand Up @@ -894,6 +898,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
let always_build_mir = debugging_opts.always_build_mir;
let no_analysis = debugging_opts.no_analysis;

if debugging_opts.debug_llvm {
Expand Down Expand Up @@ -1049,6 +1054,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
parse_only: parse_only,
no_trans: no_trans,
treat_err_as_bug: treat_err_as_bug,
always_build_mir: always_build_mir,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
Expand Down