diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 536caece21f84..e6779dfae409b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -580,6 +580,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Include assignment analysis data in --pretty flowgraph output"), flowgraph_print_all: bool = (false, parse_bool, "Include all dataflow analysis data in --pretty flowgraph output"), + pretty_keep_going: bool = (false, parse_bool, + "Do not stop after pretty-printing (use with --pretty)"), + pretty_dump_dir: Option = (None, parse_opt_string, + "The directory where --pretty output will be saved"), print_region_graph: bool = (false, parse_bool, "Prints region inference graph. \ Use with RUST_REGION_GRAPH=help for more info"), diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index ca740f5378219..c26545a42ecc6 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -30,11 +30,11 @@ pub const FN_OUTPUT_NAME: &'static str = "Output"; #[derive(Clone, Copy, Debug)] pub struct ErrorReported; -pub fn time(do_it: bool, what: &str, u: U, f: F) -> T where - F: FnOnce(U) -> T, +pub fn time(do_it: bool, what: &str, f: F) -> T where + F: FnOnce() -> T, { thread_local!(static DEPTH: Cell = Cell::new(0)); - if !do_it { return f(u); } + if !do_it { return f(); } let old = DEPTH.with(|slot| { let r = slot.get(); @@ -42,15 +42,10 @@ pub fn time(do_it: bool, what: &str, u: U, f: F) -> T where r }); - let mut u = Some(u); let mut rv = None; - let dur = { - let ref mut rvp = rv; - - Duration::span(move || { - *rvp = Some(f(u.take().unwrap())) - }) - }; + let dur = Duration::span(|| { + rv = Some(f()); + }); let rv = rv.unwrap(); println!("{}time: {}.{:03} \t{}", repeat(" ").take(old).collect::(), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 425ec7ec452ee..569edc19a7915 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -69,10 +69,18 @@ pub fn compile_input(sess: Session, let (outputs, expanded_crate, id) = { let krate = phase_1_parse_input(&sess, cfg, input); + let krate = if control.every_body_loops { + use syntax::fold::Folder; + ::pretty::ReplaceBodyWithLoop::new().fold_crate(krate) + } else { + krate + }; + controller_entry_point!(after_parse, CompileState::state_after_parse(input, &sess, outdir, + output, &krate)); let outputs = build_output_filenames(input, @@ -99,6 +107,8 @@ pub fn compile_input(sess: Session, CompileState::state_after_expand(input, &sess, outdir, + output, + &outputs, &expanded_crate, &id[..])); @@ -112,6 +122,8 @@ pub fn compile_input(sess: Session, CompileState::state_after_write_deps(input, &sess, outdir, + output, + &outputs, &ast_map, &ast_map.krate(), &id[..])); @@ -126,6 +138,8 @@ pub fn compile_input(sess: Session, CompileState::state_after_analysis(input, &analysis.ty_cx.sess, outdir, + output, + &outputs, analysis.ty_cx.map.krate(), &analysis, &analysis.ty_cx)); @@ -152,6 +166,8 @@ pub fn compile_input(sess: Session, CompileState::state_after_llvm(input, &sess, outdir, + output, + &outputs, &trans)); phase_6_link_output(&sess, &trans, &outputs); @@ -193,6 +209,7 @@ pub struct CompileController<'a> { pub after_llvm: PhaseController<'a>, pub make_glob_map: resolve::MakeGlobMap, + pub every_body_loops: bool, } impl<'a> CompileController<'a> { @@ -204,6 +221,7 @@ impl<'a> CompileController<'a> { after_analysis: PhaseController::basic(), after_llvm: PhaseController::basic(), make_glob_map: resolve::MakeGlobMap::No, + every_body_loops: false, } } } @@ -225,7 +243,7 @@ impl<'a> PhaseController<'a> { /// State that is passed to a callback. What state is available depends on when /// during compilation the callback is made. See the various constructor methods /// (`state_*`) in the impl to see which data is provided for any given entry point. -pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { +pub struct CompileState<'a, 'tcx: 'a> { pub input: &'a Input, pub session: &'a Session, pub cfg: Option<&'a ast::CrateConfig>, @@ -233,26 +251,30 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { pub crate_name: Option<&'a str>, pub output_filenames: Option<&'a OutputFilenames>, pub out_dir: Option<&'a Path>, + pub output: Option<&'a Path>, pub expanded_crate: Option<&'a ast::Crate>, - pub ast_map: Option<&'a ast_map::Map<'ast>>, + pub ast_map: Option<&'a ast_map::Map<'tcx>>, pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>, pub tcx: Option<&'a ty::ctxt<'tcx>>, pub trans: Option<&'a trans::CrateTranslation>, } -impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { +impl<'a, 'tcx> CompileState<'a, 'tcx> { fn empty(input: &'a Input, session: &'a Session, - out_dir: &'a Option) - -> CompileState<'a, 'ast, 'tcx> { + out_dir: &'a Option, + output: &'a Option, + output_filenames: Option<&'a OutputFilenames>) + -> CompileState<'a, 'tcx> { CompileState { input: input, session: session, out_dir: out_dir.as_ref(), + output: output.as_ref(), + output_filenames: output_filenames, cfg: None, krate: None, crate_name: None, - output_filenames: None, expanded_crate: None, ast_map: None, analysis: None, @@ -264,54 +286,64 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { fn state_after_parse(input: &'a Input, session: &'a Session, out_dir: &'a Option, + output: &'a Option, krate: &'a ast::Crate) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'tcx> { CompileState { krate: Some(krate), - .. CompileState::empty(input, session, out_dir) + .. CompileState::empty(input, session, out_dir, output, None) } } fn state_after_expand(input: &'a Input, session: &'a Session, out_dir: &'a Option, + output: &'a Option, + output_filenames: &'a OutputFilenames, expanded_crate: &'a ast::Crate, crate_name: &'a str) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'tcx> { CompileState { crate_name: Some(crate_name), expanded_crate: Some(expanded_crate), - .. CompileState::empty(input, session, out_dir) + .. CompileState::empty(input, session, out_dir, output, + Some(output_filenames)) } } fn state_after_write_deps(input: &'a Input, session: &'a Session, out_dir: &'a Option, - ast_map: &'a ast_map::Map<'ast>, + output: &'a Option, + output_filenames: &'a OutputFilenames, + ast_map: &'a ast_map::Map<'tcx>, expanded_crate: &'a ast::Crate, crate_name: &'a str) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'tcx> { CompileState { crate_name: Some(crate_name), ast_map: Some(ast_map), expanded_crate: Some(expanded_crate), - .. CompileState::empty(input, session, out_dir) + .. CompileState::empty(input, session, out_dir, output, + Some(output_filenames)) } } fn state_after_analysis(input: &'a Input, session: &'a Session, out_dir: &'a Option, + output: &'a Option, + output_filenames: &'a OutputFilenames, expanded_crate: &'a ast::Crate, analysis: &'a ty::CrateAnalysis<'tcx>, tcx: &'a ty::ctxt<'tcx>) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'tcx> { CompileState { analysis: Some(analysis), tcx: Some(tcx), expanded_crate: Some(expanded_crate), - .. CompileState::empty(input, session, out_dir) + .. CompileState::empty(input, session, out_dir, output, + Some(output_filenames)) } } @@ -319,11 +351,14 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { fn state_after_llvm(input: &'a Input, session: &'a Session, out_dir: &'a Option, + output: &'a Option, + output_filenames: &'a OutputFilenames, trans: &'a trans::CrateTranslation) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'tcx> { CompileState { trans: Some(trans), - .. CompileState::empty(input, session, out_dir) + .. CompileState::empty(input, session, out_dir, output, + Some(output_filenames)) } } } @@ -336,7 +371,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) syntax::ext::mtwt::reset_tables(); token::reset_ident_interner(); - let krate = time(sess.time_passes(), "parsing", (), |_| { + let krate = time(sess.time_passes(), "parsing", || { match *input { Input::File(ref file) => { parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess) @@ -383,7 +418,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, *sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs); - time(time_passes, "recursion limit", (), |_| { + time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); }); @@ -395,7 +430,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // // baz! should not use this definition unless foo is enabled. - time(time_passes, "gated macro checking", (), |_| { + time(time_passes, "gated macro checking", || { let features = syntax::feature_gate::check_crate_macros(sess.codemap(), &sess.parse_sess.span_diagnostic, @@ -406,23 +441,23 @@ pub fn phase_2_configure_and_expand(sess: &Session, sess.abort_if_errors(); }); - krate = time(time_passes, "configuration 1", krate, |krate| + krate = time(time_passes, "configuration 1", || syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); - krate = time(time_passes, "crate injection", krate, |krate| + krate = time(time_passes, "crate injection", || syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone())); - let macros = time(time_passes, "macro loading", (), |_| + let macros = time(time_passes, "macro loading", || metadata::macro_import::read_macro_defs(sess, &krate)); let mut addl_plugins = Some(addl_plugins); - let registrars = time(time_passes, "plugin loading", (), |_| + let registrars = time(time_passes, "plugin loading", || plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap())); let mut registry = Registry::new(sess, &krate); - time(time_passes, "plugin registration", registrars, |registrars| { + time(time_passes, "plugin registration", || { if sess.features.borrow().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); @@ -461,40 +496,38 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Abort if there are errors from lint processing or a plugin registrar. sess.abort_if_errors(); - krate = time(time_passes, "expansion", (krate, macros, syntax_exts), - |(krate, macros, syntax_exts)| { - // Windows dlls do not have rpaths, so they don't know how to find their - // dependencies. It's up to us to tell the system where to find all the - // dependent dlls. Note that this uses cfg!(windows) as opposed to - // targ_cfg because syntax extensions are always loaded for the host - // compiler, not for the target. - let mut _old_path = OsString::from_str(""); - if cfg!(windows) { - _old_path = env::var_os("PATH").unwrap_or(_old_path); - let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths(); - new_path.extend(os::split_paths(_old_path.to_str().unwrap()).into_iter()); - env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); - } - let features = sess.features.borrow(); - let cfg = syntax::ext::expand::ExpansionConfig { - crate_name: crate_name.to_string(), - features: Some(&features), - recursion_limit: sess.recursion_limit.get(), - }; - let ret = syntax::ext::expand::expand_crate(&sess.parse_sess, - cfg, - macros, - syntax_exts, - krate); - if cfg!(windows) { - env::set_var("PATH", &_old_path); - } - ret + krate = time(time_passes, "expansion", || { + // Windows dlls do not have rpaths, so they don't know how to find their + // dependencies. It's up to us to tell the system where to find all the + // dependent dlls. Note that this uses cfg!(windows) as opposed to + // targ_cfg because syntax extensions are always loaded for the host + // compiler, not for the target. + let mut _old_path = OsString::from_str(""); + if cfg!(windows) { + _old_path = env::var_os("PATH").unwrap_or(_old_path); + let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths(); + new_path.extend(os::split_paths(_old_path.to_str().unwrap()).into_iter()); + env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); + } + let features = sess.features.borrow(); + let cfg = syntax::ext::expand::ExpansionConfig { + crate_name: crate_name.to_string(), + features: Some(&features), + recursion_limit: sess.recursion_limit.get(), + }; + let ret = syntax::ext::expand::expand_crate(&sess.parse_sess, + cfg, + macros, + syntax_exts, + krate); + if cfg!(windows) { + env::set_var("PATH", &_old_path); } - ); + ret + }); // Needs to go *after* expansion to be able to check the results of macro expansion. - time(time_passes, "complete gated feature checking", (), |_| { + time(time_passes, "complete gated feature checking", || { let features = syntax::feature_gate::check_crate(sess.codemap(), &sess.parse_sess.span_diagnostic, @@ -506,20 +539,20 @@ pub fn phase_2_configure_and_expand(sess: &Session, // JBC: make CFG processing part of expansion to avoid this problem: // strip again, in case expansion added anything with a #[cfg]. - krate = time(time_passes, "configuration 2", krate, |krate| + krate = time(time_passes, "configuration 2", || syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); - krate = time(time_passes, "maybe building test harness", krate, |krate| + krate = time(time_passes, "maybe building test harness", || syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic())); - krate = time(time_passes, "prelude injection", krate, |krate| + krate = time(time_passes, "prelude injection", || syntax::std_inject::maybe_inject_prelude(krate)); - time(time_passes, "checking that all macro invocations are gone", &krate, |krate| - syntax::ext::expand::check_for_macros(&sess.parse_sess, krate)); + time(time_passes, "checking that all macro invocations are gone", || + syntax::ext::expand::check_for_macros(&sess.parse_sess, &krate)); Some(krate) } @@ -538,7 +571,7 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session, } } - let map = time(sess.time_passes(), "assigning node ids and indexing ast", forest, |forest| + let map = time(sess.time_passes(), "assigning node ids and indexing ast", move || ast_map::map_crate(forest, NodeIdAssigner { sess: sess })); if sess.opts.debugging_opts.ast_json { @@ -560,10 +593,10 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, let time_passes = sess.time_passes(); let krate = ast_map.krate(); - time(time_passes, "external crate/lib resolution", (), |_| + time(time_passes, "external crate/lib resolution", || CrateReader::new(&sess).read_crates(krate)); - let lang_items = time(time_passes, "language item collection", (), |_| + let lang_items = time(time_passes, "language item collection", || middle::lang_items::collect_language_items(krate, &sess)); let resolve::CrateMap { @@ -573,35 +606,34 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, trait_map, external_exports, glob_map, - } = - time(time_passes, "resolution", (), - |_| resolve::resolve_crate(&sess, - &ast_map, - &lang_items, - krate, - make_glob_map)); + } = time(time_passes, "resolution", || + resolve::resolve_crate(&sess, + &ast_map, + &lang_items, + krate, + make_glob_map)); // Discard MTWT tables that aren't required past resolution. syntax::ext::mtwt::clear_tables(); - let named_region_map = time(time_passes, "lifetime resolution", (), - |_| middle::resolve_lifetime::krate(&sess, krate, &def_map)); + let named_region_map = time(time_passes, "lifetime resolution", || + middle::resolve_lifetime::krate(&sess, krate, &def_map)); - time(time_passes, "looking for entry point", (), - |_| middle::entry::find_entry_point(&sess, &ast_map)); + time(time_passes, "looking for entry point", || + middle::entry::find_entry_point(&sess, &ast_map)); sess.plugin_registrar_fn.set( - time(time_passes, "looking for plugin registrar", (), |_| + time(time_passes, "looking for plugin registrar", || plugin::build::find_plugin_registrar( sess.diagnostic(), krate))); - let region_map = time(time_passes, "region resolution", (), |_| + let region_map = time(time_passes, "region resolution", || middle::region::resolve_crate(&sess, krate)); - time(time_passes, "loop checking", (), |_| + time(time_passes, "loop checking", || middle::check_loop::check_crate(&sess, krate)); - time(time_passes, "static item recursion checking", (), |_| + time(time_passes, "static item recursion checking", || middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map)); let ty_cx = ty::mk_ctxt(sess, @@ -617,33 +649,33 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, // passes are timed inside typeck typeck::check_crate(&ty_cx, trait_map); - time(time_passes, "const checking", (), |_| + time(time_passes, "const checking", || middle::check_const::check_crate(&ty_cx)); let (exported_items, public_items) = - time(time_passes, "privacy checking", (), |_| + time(time_passes, "privacy checking", || rustc_privacy::check_crate(&ty_cx, &export_map, external_exports)); // Do not move this check past lint - time(time_passes, "stability index", (), |_| + time(time_passes, "stability index", || ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items)); - time(time_passes, "intrinsic checking", (), |_| + time(time_passes, "intrinsic checking", || middle::intrinsicck::check_crate(&ty_cx)); - time(time_passes, "effect checking", (), |_| + time(time_passes, "effect checking", || middle::effect::check_crate(&ty_cx)); - time(time_passes, "match checking", (), |_| + time(time_passes, "match checking", || middle::check_match::check_crate(&ty_cx)); - time(time_passes, "liveness checking", (), |_| + time(time_passes, "liveness checking", || middle::liveness::check_crate(&ty_cx)); - time(time_passes, "borrow checking", (), |_| + time(time_passes, "borrow checking", || borrowck::check_crate(&ty_cx)); - time(time_passes, "rvalue checking", (), |_| + time(time_passes, "rvalue checking", || middle::check_rvalues::check_crate(&ty_cx, krate)); // Avoid overwhelming user with errors if type checking failed. @@ -654,24 +686,24 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, ty_cx.sess.abort_if_errors(); let reachable_map = - time(time_passes, "reachability checking", (), |_| + time(time_passes, "reachability checking", || reachable::find_reachable(&ty_cx, &exported_items)); - time(time_passes, "death checking", (), |_| { + time(time_passes, "death checking", || { middle::dead::check_crate(&ty_cx, &exported_items, &reachable_map) }); let ref lib_features_used = - time(time_passes, "stability checking", (), |_| + time(time_passes, "stability checking", || stability::check_unstable_api_usage(&ty_cx)); - time(time_passes, "unused lib feature checking", (), |_| + time(time_passes, "unused lib feature checking", || stability::check_unused_or_stable_features( &ty_cx.sess, lib_features_used)); - time(time_passes, "lint checking", (), |_| + time(time_passes, "lint checking", || lint::check_crate(&ty_cx, &exported_items)); // The above three passes generate errors w/o aborting @@ -694,11 +726,11 @@ pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>) -> (ty::ctxt<'tcx>, trans::CrateTranslation) { let time_passes = analysis.ty_cx.sess.time_passes(); - time(time_passes, "resolving dependency formats", (), |_| + time(time_passes, "resolving dependency formats", || dependency_format::calculate(&analysis.ty_cx)); // Option dance to work around the lack of stack once closures. - time(time_passes, "translation", analysis, |analysis| + time(time_passes, "translation", || trans::trans_crate(analysis)) } @@ -710,7 +742,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, if sess.opts.cg.no_integrated_as { let output_type = config::OutputTypeAssembly; - time(sess.time_passes(), "LLVM passes", (), |_| + time(sess.time_passes(), "LLVM passes", || write::run_passes(sess, trans, &[output_type], outputs)); write::run_assembler(sess, outputs); @@ -720,7 +752,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, fs::unlink(&outputs.temp_path(config::OutputTypeAssembly)).unwrap(); } } else { - time(sess.time_passes(), "LLVM passes", (), |_| + time(sess.time_passes(), "LLVM passes", || write::run_passes(sess, trans, &sess.opts.output_types, @@ -740,7 +772,7 @@ pub fn phase_6_link_output(sess: &Session, new_path.extend(os::split_paths(old_path.to_str().unwrap()).into_iter()); env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap()); - time(sess.time_passes(), "linking", (), |_| + time(sess.time_passes(), "linking", || link::link_binary(sess, trans, outputs, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 15fae351ddbf2..cbf5f5eccf83f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -98,7 +98,7 @@ const BUG_REPORT_URL: &'static str = pub fn run(args: Vec) -> int { - monitor(move || run_compiler(&args, &mut RustcDefaultCalls)); + monitor(move || run_compiler(&args, &mut RustcDefaultCalls::new())); 0 } @@ -142,17 +142,6 @@ pub fn run_compiler<'a>(args: &[String], do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); - // It is somewhat unfortunate that this is hardwired in - this is forced by - // the fact that pretty_print_input requires the session by value. - let pretty = callbacks.parse_pretty(&sess, &matches); - match pretty { - Some((ppm, opt_uii)) => { - pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile); - return; - } - None => {/* continue */ } - } - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); let control = callbacks.build_controller(&sess); driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control); @@ -239,33 +228,15 @@ pub trait CompilerCalls<'a> { &diagnostics::registry::Registry) -> Option<(Input, Option)>; - // Parse pretty printing information from the arguments. The implementer can - // choose to ignore this (the default will return None) which will skip pretty - // printing. If you do want to pretty print, it is recommended to use the - // implementation of this method from RustcDefaultCalls. - // FIXME, this is a terrible bit of API. Parsing of pretty printing stuff - // should be done as part of the framework and the implementor should customise - // handling of it. However, that is not possible atm because pretty printing - // essentially goes off and takes another path through the compiler which - // means the session is either moved or not depending on what parse_pretty - // returns (we could fix this by cloning, but it's another hack). The proper - // solution is to handle pretty printing as if it were a compiler extension, - // extending CompileController to make this work (see for example the treatment - // of save-analysis in RustcDefaultCalls::build_controller). - fn parse_pretty(&mut self, - _sess: &Session, - _matches: &getopts::Matches) - -> Option<(PpMode, Option)> { - None - } - // Create a CompilController struct for controlling the behaviour of compilation. fn build_controller(&mut self, &Session) -> CompileController<'a>; } // CompilerCalls instance for a regular rustc build. -#[derive(Copy)] -pub struct RustcDefaultCalls; +pub struct RustcDefaultCalls { + save_analysis: bool, + pretty_print: Option<(PpMode, Option)> +} impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, @@ -320,28 +291,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { None } - fn parse_pretty(&mut self, - sess: &Session, - matches: &getopts::Matches) - -> Option<(PpMode, Option)> { - let pretty = if sess.opts.debugging_opts.unstable_options { - matches.opt_default("pretty", "normal").map(|a| { - // stable pretty-print variants only - pretty::parse_pretty(sess, &a, false) - }) - } else { - None - }; - if pretty.is_none() && sess.unstable_options() { - matches.opt_str("xpretty").map(|a| { - // extended with unstable pretty-print variants - pretty::parse_pretty(sess, &a, true) - }) - } else { - pretty - } - } - fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, @@ -349,6 +298,18 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { odir: &Option, ofile: &Option) -> Compilation { + self.save_analysis = sess.opts.debugging_opts.save_analysis; + + if sess.unstable_options() { + self.pretty_print = matches.opt_default("pretty", "normal").map(|a| { + // stable pretty-print variants only + pretty::parse_pretty(&a, false).unwrap_or_else(|e| sess.fatal(&e)) + }).or_else(|| matches.opt_str("xpretty").map(|a| { + // extended with unstable pretty-print variants + pretty::parse_pretty(&a, true).unwrap_or_else(|e| sess.fatal(&e)) + })); + } + RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile).and_then( || RustcDefaultCalls::list_metadata(sess, matches, input)) } @@ -374,15 +335,20 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_llvm.stop = Compilation::Stop; } - if sess.opts.debugging_opts.save_analysis { + pretty::setup_controller(&mut control, + self.pretty_print.take(), + sess.opts.debugging_opts.pretty_dump_dir + .as_ref().map(|s| &s[..]), + sess.opts.debugging_opts.pretty_keep_going); + + if self.save_analysis { control.after_analysis.callback = box |state| { time(state.session.time_passes(), - "save analysis", - state.expanded_crate.unwrap(), - |krate| save::process_crate(state.session, - krate, - state.analysis.unwrap(), - state.out_dir)); + "save analysis", || + save::process_crate(state.session, + state.expanded_crate.unwrap(), + state.analysis.unwrap(), + state.out_dir)); }; control.make_glob_map = resolve::MakeGlobMap::Yes; } @@ -392,6 +358,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } impl RustcDefaultCalls { + pub fn new() -> RustcDefaultCalls { + RustcDefaultCalls { + save_analysis: false, + pretty_print: None + } + } + pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 22473099baf60..9bdb99d27f8c9 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -15,19 +15,15 @@ pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; -use rustc_trans::back::link; - use driver; use rustc::middle::ty; use rustc::middle::cfg; use rustc::middle::cfg::graphviz::LabelledCFG; use rustc::session::Session; -use rustc::session::config::Input; use rustc::util::ppaux; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; -use rustc_resolve as resolve; use syntax::ast; use syntax::ast_map::{self, blocks, NodePrinter}; @@ -38,8 +34,11 @@ use syntax::ptr::P; use graphviz as dot; -use std::old_io::{self, MemReader}; +use std::borrow::{Cow, IntoCow}; +use std::env; +use std::old_io::{self, BufReader}; use std::option; +use std::os; use std::str::FromStr; #[derive(Copy, PartialEq, Debug)] @@ -48,6 +47,7 @@ pub enum PpSourceMode { PpmEveryBodyLoops, PpmExpanded, PpmTyped, + PpmTypedUnsuffixedLiterals, PpmIdentified, PpmExpandedIdentified, PpmExpandedHygiene, @@ -69,9 +69,8 @@ pub enum PpMode { PpmFlowGraph(PpFlowGraphMode), } -pub fn parse_pretty(sess: &Session, - name: &str, - extended: bool) -> (PpMode, Option) { +pub fn parse_pretty(name: &str, extended: bool) + -> Result<(PpMode, Option), String> { let mut split = name.splitn(1, '='); let first = split.next().unwrap(); let opt_second = split.next(); @@ -80,132 +79,38 @@ pub fn parse_pretty(sess: &Session, ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops), ("expanded", _) => PpmSource(PpmExpanded), ("typed", _) => PpmSource(PpmTyped), + ("typed,unsuffixed_literals", true) => PpmSource(PpmTypedUnsuffixedLiterals), ("expanded,identified", _) => PpmSource(PpmExpandedIdentified), ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene), ("identified", _) => PpmSource(PpmIdentified), ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), - _ => { + _ => return Err({ if extended { - sess.fatal(&format!( + format!( "argument to `xpretty` must be one of `normal`, \ - `expanded`, `flowgraph[,unlabelled]=`, `typed`, `identified`, \ - `expanded,identified`, or `everybody_loops`; got {}", name)); + `expanded`, `flowgraph[,unlabelled]=`, `typed`, \ + `typed,unsuffixed_literals`, `identified`, \ + `expanded,identified`, or `everybody_loops`; got {}", name) } else { - sess.fatal(&format!( + format!( "argument to `pretty` must be one of `normal`, \ `expanded`, `typed`, `identified`, \ - or `expanded,identified`; got {}", name)); + or `expanded,identified`; got {}", name) } - } + }) }; let opt_second = opt_second.and_then(|s| s.parse::().ok()); - (first, opt_second) -} - - - -// This slightly awkward construction is to allow for each PpMode to -// choose whether it needs to do analyses (which can consume the -// Session) and then pass through the session (now attached to the -// analysis results) on to the chosen pretty-printer, along with the -// `&PpAnn` object. -// -// Note that since the `&PrinterSupport` is freshly constructed on each -// call, it would not make sense to try to attach the lifetime of `self` -// to the lifetime of the `&PrinterObject`. -// -// (The `use_once_payload` is working around the current lack of once -// functions in the compiler.) - -impl PpSourceMode { - /// Constructs a `PrinterSupport` object and passes it to `f`. - fn call_with_pp_support<'tcx, A, B, F>(&self, - sess: Session, - ast_map: Option>, - arenas: &'tcx ty::CtxtArenas<'tcx>, - id: String, - payload: B, - f: F) -> A where - F: FnOnce(&PrinterSupport, B) -> A, - { - match *self { - PpmNormal | PpmEveryBodyLoops | PpmExpanded => { - let annotation = NoAnn { sess: sess, ast_map: ast_map }; - f(&annotation, payload) - } - - PpmIdentified | PpmExpandedIdentified => { - let annotation = IdentifiedAnnotation { sess: sess, ast_map: ast_map }; - f(&annotation, payload) - } - PpmExpandedHygiene => { - let annotation = HygieneAnnotation { sess: sess, ast_map: ast_map }; - f(&annotation, payload) - } - PpmTyped => { - let ast_map = ast_map.expect("--pretty=typed missing ast_map"); - let analysis = driver::phase_3_run_analysis_passes(sess, - ast_map, - arenas, - id, - resolve::MakeGlobMap::No); - let annotation = TypedAnnotation { analysis: analysis }; - f(&annotation, payload) - } - } - } -} - -trait PrinterSupport<'ast>: pprust::PpAnn { - /// Provides a uniform interface for re-extracting a reference to a - /// `Session` from a value that now owns it. - fn sess<'a>(&'a self) -> &'a Session; - - /// Provides a uniform interface for re-extracting a reference to an - /// `ast_map::Map` from a value that now owns it. - fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>>; - - /// Produces the pretty-print annotation object. - /// - /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its super-traits.) - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn; -} - -struct NoAnn<'ast> { - sess: Session, - ast_map: Option> -} - -impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } - - fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> { - self.ast_map.as_ref() - } - - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self } + Ok((first, opt_second)) } -impl<'ast> pprust::PpAnn for NoAnn<'ast> {} - -struct IdentifiedAnnotation<'ast> { - sess: Session, - ast_map: Option>, -} - -impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } - - fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> { - self.ast_map.as_ref() - } - - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self } -} +struct NoAnn; +const NO_ANNOTATION: &'static pprust::PpAnn = &NoAnn; +impl pprust::PpAnn for NoAnn {} -impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { +struct IdentifiedAnnotation; +const IDENTIFIED_ANNOTATION: &'static pprust::PpAnn = &IdentifiedAnnotation; +impl pprust::PpAnn for IdentifiedAnnotation { fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> old_io::IoResult<()> { @@ -241,22 +146,9 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { } } -struct HygieneAnnotation<'ast> { - sess: Session, - ast_map: Option>, -} - -impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } - - fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> { - self.ast_map.as_ref() - } - - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self } -} - -impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { +struct HygieneAnnotation; +const HYGIENE_ANNOTATION: &'static pprust::PpAnn = &HygieneAnnotation; +impl pprust::PpAnn for HygieneAnnotation { fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> old_io::IoResult<()> { @@ -276,22 +168,12 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { } } - -struct TypedAnnotation<'tcx> { - analysis: ty::CrateAnalysis<'tcx>, -} - -impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> { - fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess } - - fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> { - Some(&self.analysis.ty_cx.map) - } - - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self } +#[derive(Copy)] +struct TypedAnnotation<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, } -impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> { +impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> { fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> old_io::IoResult<()> { @@ -303,16 +185,13 @@ impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> { fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> old_io::IoResult<()> { - let tcx = &self.analysis.ty_cx; match node { pprust::NodeExpr(expr) => { - try!(pp::space(&mut s.s)); - try!(pp::word(&mut s.s, "as")); - try!(pp::space(&mut s.s)); + try!(s.word_space(":")); try!(pp::word(&mut s.s, &ppaux::ty_to_string( - tcx, - ty::expr_ty(tcx, expr)))); + self.tcx, + ty::expr_ty(self.tcx, expr)))); s.pclose() } _ => Ok(()) @@ -320,6 +199,44 @@ impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> { } } +struct UnsuffixedLitAnnotation { + ann: A +} + +impl pprust::PpAnn for UnsuffixedLitAnnotation { + fn pre(&self, + s: &mut pprust::State, + node: pprust::AnnNode) -> old_io::IoResult<()> { + self.ann.pre(s, node) + } + fn post(&self, + s: &mut pprust::State, + node: pprust::AnnNode) -> old_io::IoResult<()> { + self.ann.post(s, node) + } + fn literal_to_string<'a>(&self, + s: &mut pprust::State, + lit: &'a ast::Lit) -> Cow<'a, str> { + match lit.node { + ast::LitInt(i, t) => { + match t { + ast::UnsignedIntLit(_) | + ast::SignedIntLit(_, ast::Plus) | + ast::UnsuffixedIntLit(ast::Plus) => { + format!("{}", i) + } + ast::SignedIntLit(_, ast::Minus) | + ast::UnsuffixedIntLit(ast::Minus) => { + format!("-{}", i) + } + }.into_cow() + } + ast::LitFloat(ref f, _) => f.into_cow(), + _ => self.ann.literal_to_string(s, lit) + } + } +} + fn gather_flowgraph_variants(sess: &Session) -> Vec { let print_loans = sess.opts.debugging_opts.flowgraph_print_loans; let print_moves = sess.opts.debugging_opts.flowgraph_print_moves; @@ -387,7 +304,8 @@ impl UserIdentifiedItem { } } - fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -> ast::NodeId { + fn to_one_node_id(&self, user_option: &str, sess: &Session, map: &ast_map::Map) + -> ast::NodeId { let fail_because = |is_wrong_because| -> ast::NodeId { let message = format!("{} needs NodeId (int) or unique \ @@ -416,40 +334,12 @@ impl UserIdentifiedItem { } } -fn needs_ast_map(ppm: &PpMode, opt_uii: &Option) -> bool { - match *ppm { - PpmSource(PpmNormal) | - PpmSource(PpmEveryBodyLoops) | - PpmSource(PpmIdentified) => opt_uii.is_some(), - - PpmSource(PpmExpanded) | - PpmSource(PpmExpandedIdentified) | - PpmSource(PpmExpandedHygiene) | - PpmSource(PpmTyped) | - PpmFlowGraph(_) => true - } -} - -fn needs_expansion(ppm: &PpMode) -> bool { - match *ppm { - PpmSource(PpmNormal) | - PpmSource(PpmEveryBodyLoops) | - PpmSource(PpmIdentified) => false, - - PpmSource(PpmExpanded) | - PpmSource(PpmExpandedIdentified) | - PpmSource(PpmExpandedHygiene) | - PpmSource(PpmTyped) | - PpmFlowGraph(_) => true - } -} - -struct ReplaceBodyWithLoop { +pub struct ReplaceBodyWithLoop { within_static_or_const: bool, } impl ReplaceBodyWithLoop { - fn new() -> ReplaceBodyWithLoop { + pub fn new() -> ReplaceBodyWithLoop { ReplaceBodyWithLoop { within_static_or_const: false } } } @@ -502,113 +392,195 @@ impl fold::Folder for ReplaceBodyWithLoop { } } -pub fn pretty_print_input(sess: Session, - cfg: ast::CrateConfig, - input: &Input, - ppm: PpMode, - opt_uii: Option, - ofile: Option) { - let krate = driver::phase_1_parse_input(&sess, cfg, input); - - let krate = if let PpmSource(PpmEveryBodyLoops) = ppm { - let mut fold = ReplaceBodyWithLoop::new(); - fold.fold_crate(krate) - } else { - krate +pub fn setup_controller(control: &mut driver::CompileController, + ppm_and_uui: Option<(PpMode, Option)>, + dump_dir: Option<&str>, + keep_going: bool) { + + fn mk_absolute(path: &str) -> Path { + let path = os::getcwd().unwrap().join(path); + assert!(path.is_absolute()); + path + } + + let (ppm, opt_uii, dump_dir, keep_going) = match ppm_and_uui { + Some((ppm, opt_uii)) => { + (ppm, opt_uii, dump_dir.map(mk_absolute), keep_going) + } + None => { + let decoded = env::var("RUSTC_PRETTY_DUMP").ok().and_then(|s| { + let mut s = s.split(":"); + + s.next().and_then(|mode| { + parse_pretty(mode, true).ok() + }).and_then(|(ppm, opt_uii)| { + s.next().map(|dump_dir| { + (ppm, opt_uii, Some(mk_absolute(dump_dir)), true) + }) + }) + }); + if let Some(parts) = decoded { + parts + } else { + return; + } + } }; - let id = link::find_crate_name(Some(&sess), &krate.attrs, input); + if ppm == PpmSource(PpmEveryBodyLoops) { + control.every_body_loops = true; + } + + let phase = match ppm { + PpmSource(PpmNormal) | + PpmSource(PpmEveryBodyLoops) | + PpmSource(PpmIdentified) => { + if opt_uii.is_some() { + &mut control.after_write_deps + } else { + &mut control.after_parse + } + } + + PpmSource(PpmExpanded) | + PpmSource(PpmExpandedIdentified) | + PpmSource(PpmExpandedHygiene) => { + &mut control.after_write_deps + } - let is_expanded = needs_expansion(&ppm); - let compute_ast_map = needs_ast_map(&ppm, &opt_uii); - let krate = if compute_ast_map { - match driver::phase_2_configure_and_expand(&sess, krate, &id[..], None) { - None => return, - Some(k) => k + PpmSource(PpmTyped) | + PpmSource(PpmTypedUnsuffixedLiterals) | + PpmFlowGraph(_) => { + &mut control.after_analysis } - } else { - krate }; - let mut forest = ast_map::Forest::new(krate); - let arenas = ty::CtxtArenas::new(); + phase.callback = box move |state| { + let pretty_output_path; + let output = if let Some(ref dir) = dump_dir { + let file_path = if let Some(outputs) = state.output_filenames { + outputs.with_extension("rs") + } else { + state.session.fatal( + "-Z pretty-dump-dir cannot be used with --pretty \ + options that print before expansion"); + }; + let file_path = os::getcwd().unwrap().join(&file_path); + assert!(file_path.is_absolute()); + + // Cheap isomorphism: /foo/bar--bar/baz <-> foo--bar----bar--baz. + let components: Vec<_> = file_path.components().map(|bytes| { + String::from_utf8_lossy(bytes).replace("--", "----") + }).collect(); - let (krate, ast_map) = if compute_ast_map { - let map = driver::assign_node_ids_and_map(&sess, &mut forest); - (map.krate(), Some(map)) - } else { - (forest.krate(), None) + pretty_output_path = dir.join(components.connect("--")); + Some(&pretty_output_path) + } else { + state.output + }; + print_from_phase(state, ppm, opt_uii.as_ref(), output).unwrap(); }; - let src_name = driver::source_name(input); - let src = sess.codemap().get_filemap(&src_name[..]) - .src.as_bytes().to_vec(); - let mut rdr = MemReader::new(src); + if !keep_going { + phase.stop = ::Compilation::Stop; + } +} - let out = match ofile { +fn print_from_phase(state: driver::CompileState, + ppm: PpMode, + opt_uii: Option<&UserIdentifiedItem>, + output: Option<&Path>) + -> old_io::IoResult<()> { + let sess = state.session; + let krate = state.krate.or(state.expanded_crate) + .expect("--pretty=typed missing crate"); + let ast_map = state.ast_map.or_else(|| state.tcx.map(|tcx| &tcx.map)); + + let out = match output { None => box old_io::stdout() as Box, Some(p) => { - let r = old_io::File::create(&p); - match r { + match old_io::File::create(p) { Ok(w) => box w as Box, Err(e) => panic!("print-print failed to open {} due to {}", - p.display(), e), + p.display(), e), } } }; - match (ppm, opt_uii) { - (PpmSource(s), None) => - s.call_with_pp_support( - sess, ast_map, &arenas, id, out, |annotation, out| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - pprust::print_crate(sess.codemap(), - sess.diagnostic(), - krate, - src_name.to_string(), - &mut rdr, - out, - annotation.pp_ann(), - is_expanded) - }), + match ppm { + PpmSource(mode) => { + debug!("pretty printing source code {:?}", mode); - (PpmSource(s), Some(uii)) => - s.call_with_pp_support( - sess, ast_map, &arenas, id, (out,uii), |annotation, (out,uii)| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let ast_map = annotation.ast_map() - .expect("--pretty missing ast_map"); - let mut pp_state = - pprust::State::new_from_input(sess.codemap(), - sess.diagnostic(), - src_name.to_string(), - &mut rdr, - out, - annotation.pp_ann(), - is_expanded); - for node_id in uii.all_matching_node_ids(ast_map) { - let node = ast_map.get(node_id); - try!(pp_state.print_node(&node)); - try!(pp::space(&mut pp_state.s)); - try!(pp_state.synth_comment(ast_map.path_to_string(node_id))); - try!(pp::hardbreak(&mut pp_state.s)); - } - pp::eof(&mut pp_state.s) - }), + let typed_ann = state.tcx.map(|tcx| TypedAnnotation { tcx: tcx }); + let typed_unsuffixed_lit_ann = typed_ann.map(|ann| { + UnsuffixedLitAnnotation { ann: ann } + }); + let annotation: &pprust::PpAnn = match mode { + PpmNormal | PpmEveryBodyLoops | PpmExpanded => { + NO_ANNOTATION + } + PpmIdentified | PpmExpandedIdentified => { + IDENTIFIED_ANNOTATION + } + PpmExpandedHygiene => { + HYGIENE_ANNOTATION + } + PpmTyped => { + typed_ann.as_ref().expect("--pretty=typed missing type context") + } + PpmTypedUnsuffixedLiterals => { + typed_unsuffixed_lit_ann.as_ref().expect( + "--xpretty=typed,unsuffixed_literals missing type context") + } + }; + + let is_expanded = ast_map.is_some(); + + let src_name = driver::source_name(state.input); + let filemap = sess.codemap().get_filemap(&src_name); + let mut rdr = BufReader::new(filemap.src.as_bytes()); + + if let Some(uii) = opt_uii { + let ast_map = ast_map.expect("--pretty missing ast_map"); + let mut pp_state = + pprust::State::new_from_input(sess.codemap(), + sess.diagnostic(), + src_name, + &mut rdr, + out, + annotation, + is_expanded); + for node_id in uii.all_matching_node_ids(ast_map) { + let node = ast_map.get(node_id); + try!(pp_state.print_node(&node)); + try!(pp::space(&mut pp_state.s)); + try!(pp_state.synth_comment(ast_map.path_to_string(node_id))); + try!(pp::hardbreak(&mut pp_state.s)); + } + pp::eof(&mut pp_state.s) + } else { + pprust::print_crate(sess.codemap(), + sess.diagnostic(), + krate, + src_name, + &mut rdr, + out, + annotation, + is_expanded) + } + } - (PpmFlowGraph(mode), opt_uii) => { + PpmFlowGraph(mode) => { debug!("pretty printing flow graph for {:?}", opt_uii); let uii = opt_uii.unwrap_or_else(|| { sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or unique path suffix (b::c::d)")) }); - let ast_map = ast_map.expect("--pretty flowgraph missing ast_map"); - let nodeid = uii.to_one_node_id("--pretty", &sess, &ast_map); + let tcx = state.tcx.expect("--pretty flowgraph missing type context"); + let nodeid = uii.to_one_node_id("--pretty", sess, &tcx.map); - let node = ast_map.find(nodeid).unwrap_or_else(|| { + let node = tcx.map.find(nodeid).unwrap_or_else(|| { sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) }); @@ -616,13 +588,8 @@ pub fn pretty_print_input(sess: Session, let code = blocks::Code::from_node(node); match code { Some(code) => { - let variants = gather_flowgraph_variants(&sess); - let analysis = driver::phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - id, - resolve::MakeGlobMap::No); - print_flowgraph(variants, analysis, code, mode, out) + let variants = gather_flowgraph_variants(sess); + print_flowgraph(variants, tcx, code, mode, out) } None => { let message = format!("--pretty=flowgraph needs \ @@ -631,29 +598,28 @@ pub fn pretty_print_input(sess: Session, // point to what was found, if there's an // accessible span. - match ast_map.opt_span(nodeid) { + match tcx.map.opt_span(nodeid) { Some(sp) => sess.span_fatal(sp, &message[..]), None => sess.fatal(&message[..]) } } } } - }.unwrap() + } } fn print_flowgraph(variants: Vec, - analysis: ty::CrateAnalysis, - code: blocks::Code, - mode: PpFlowGraphMode, - mut out: W) -> old_io::IoResult<()> { - let ty_cx = &analysis.ty_cx; + tcx: &ty::ctxt, + code: blocks::Code, + mode: PpFlowGraphMode, + mut out: W) -> old_io::IoResult<()> { let cfg = match code { - blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block), - blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()), + blocks::BlockCode(block) => cfg::CFG::new(tcx, &*block), + blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &*fn_like.body()), }; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { - ast_map: &ty_cx.map, + ast_map: &tcx.map, cfg: &cfg, name: format!("node_{}", code.id()), labelled_edges: labelled_edges, @@ -665,14 +631,14 @@ fn print_flowgraph(variants: Vec, return expand_err_details(r); } blocks::BlockCode(_) => { - ty_cx.sess.err("--pretty flowgraph with -Z flowgraph-print \ - annotations requires fn-like node id."); + tcx.sess.err("--pretty flowgraph with -Z flowgraph-print \ + annotations requires fn-like node id."); return Ok(()) } blocks::FnLikeCode(fn_like) => { let fn_parts = borrowck::FnPartsWithCFG::from_fn_like(&fn_like, &cfg); let (bccx, analysis_data) = - borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts); + borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_parts); let lcfg = borrowck_dot::DataflowLabeller { inner: lcfg, diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 7b377ac3611b6..d54c9e0a53039 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -788,7 +788,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, // Invoke the system linker debug!("{:?}", &cmd); - let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output()); + let prog = time(sess.time_passes(), "running linker", || cmd.output()); match prog { Ok(prog) => { if !prog.status.success() { @@ -1190,7 +1190,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, let name = &name[3..name.len() - 5]; // chop off lib/.rlib time(sess.time_passes(), &format!("altering {}.rlib", name), - (), |()| { + || { let dst = tmpdir.join(cratepath.filename().unwrap()); match fs::copy(&cratepath, &dst) { Ok(..) => {} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index d8a296bf0410c..f51b8ad2ac288 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -65,11 +65,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, for i in iter::count(0, 1) { let bc_encoded = time(sess.time_passes(), &format!("check for {}.{}.bytecode.deflate", name, i), - (), - |_| { - archive.read(&format!("{}.{}.bytecode.deflate", - file, i)) - }); + || archive.read(&format!("{}.{}.bytecode.deflate", + file, i))); let bc_encoded = match bc_encoded { Some(data) => data, None => { @@ -84,7 +81,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }; let bc_decoded = if is_versioned_bytecode_format(bc_encoded) { - time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| { + time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), || { // Read the version let version = extract_bytecode_format_version(bc_encoded); @@ -108,7 +105,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } }) } else { - time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| { + time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), || { // the object must be in the old, pre-versioning format, so simply // inflate everything and let LLVM decide if it can make sense of it match flate::inflate_bytes(bc_encoded) { @@ -125,8 +122,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, debug!("linking {}, part {}", name, i); time(sess.time_passes(), &format!("ll link {}.{}", name, i), - (), - |()| unsafe { + || unsafe { if !llvm::LLVMRustLinkInExternalBitcode(llmod, ptr as *const libc::c_char, bc_decoded.len() as libc::size_t) { @@ -183,7 +179,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); - time(sess.time_passes(), "LTO passes", (), |()| + time(sess.time_passes(), "LTO passes", || llvm::LLVMRunPassManager(pm, llmod)); llvm::LLVMDisposePassManager(pm); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index cd14fe529b1a7..c712a2f261384 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -460,9 +460,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } // Finally, run the actual optimization passes - time(config.time_passes, "llvm function passes", (), |()| + time(config.time_passes, "llvm function passes", || llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); - time(config.time_passes, "llvm module passes", (), |()| + time(config.time_passes, "llvm module passes", || llvm::LLVMRunPassManager(mpm, llmod)); // Deallocate managers that we're now done with @@ -471,7 +471,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, match cgcx.lto_ctxt { Some((sess, reachable)) if sess.lto() => { - time(sess.time_passes(), "all lto passes", (), |()| + time(sess.time_passes(), "all lto passes", || lto::run(sess, llmod, tm, reachable)); if config.emit_lto_bc { @@ -515,7 +515,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } - time(config.time_passes, "codegen passes", (), |()| { + time(config.time_passes, "codegen passes", || { if config.emit_ir { let ext = format!("{}.ll", name_extra); let out = output_names.with_extension(&ext); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 78dd66c8e7dbb..4d8b1d1c0e8d2 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -326,20 +326,20 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { tcx: tcx }; - time(time_passes, "type collecting", (), |_| + time(time_passes, "type collecting", || collect::collect_item_types(tcx)); // this ensures that later parts of type checking can assume that items // have valid types and not error tcx.sess.abort_if_errors(); - time(time_passes, "variance inference", (), |_| + time(time_passes, "variance inference", || variance::infer_variance(tcx)); - time(time_passes, "coherence checking", (), |_| + time(time_passes, "coherence checking", || coherence::check_coherence(&ccx)); - time(time_passes, "type checking", (), |_| + time(time_passes, "type checking", || check::check_item_types(&ccx)); check_for_entry_fn(&ccx); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 43e8f44244e78..656e267dcc9a3 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -24,7 +24,7 @@ use rustc_lint; use rustc::session::{self, config}; use rustc::session::config::get_unstable_features_setting; use rustc::session::search_paths::{SearchPaths, PathKind}; -use rustc_driver::{driver, Compilation}; +use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls}; use syntax::codemap::CodeMap; use syntax::diagnostic; @@ -117,8 +117,8 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, let sessopts = config::Options { maybe_sysroot: Some(os::self_exe_name().unwrap().dir_path().dir_path()), search_paths: libs, - crate_types: vec!(config::CrateTypeExecutable), - output_types: vec!(config::OutputTypeExe), + crate_types: vec![config::CrateTypeExecutable], + output_types: vec![config::OutputTypeExe], externs: externs, cg: config::CodegenOptions { prefer_dynamic: true, @@ -126,6 +126,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, }, test: as_test_harness, unstable_features: get_unstable_features_setting(), + no_trans: no_run, ..config::basic_options().clone() }; @@ -173,10 +174,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, let out = Some(outdir.path().clone()); let cfg = config::build_configuration(&sess); let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); - let mut control = driver::CompileController::basic(); - if no_run { - control.after_analysis.stop = Compilation::Stop; - } + let control = RustcDefaultCalls::new().build_controller(&sess); driver::compile_input(sess, cfg, &input, &out, &None, None, control); if no_run { return } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 544fb15dcde7b..3c137351e3814 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -199,7 +199,7 @@ pub mod rt { fn to_source(&self) -> String { let lit = dummy_spanned(ast::LitStr( token::intern_and_get_ident(self), ast::CookedStr)); - pprust::lit_to_string(&lit) + pprust::lit_to_string(&lit).into_owned() } } impl ToSourceWithHygiene for str { @@ -222,7 +222,7 @@ pub mod rt { impl ToSource for bool { fn to_source(&self) -> String { let lit = dummy_spanned(ast::LitBool(*self)); - pprust::lit_to_string(&lit) + pprust::lit_to_string(&lit).into_owned() } } impl ToSourceWithHygiene for bool { @@ -234,7 +234,7 @@ pub mod rt { impl ToSource for char { fn to_source(&self) -> String { let lit = dummy_spanned(ast::LitChar(*self)); - pprust::lit_to_string(&lit) + pprust::lit_to_string(&lit).into_owned() } } impl ToSourceWithHygiene for char { @@ -249,7 +249,7 @@ pub mod rt { fn to_source(&self) -> String { let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag, ast::Sign::new(*self))); - pprust::lit_to_string(&dummy_spanned(lit)) + pprust::lit_to_string(&dummy_spanned(lit)).into_owned() } } impl ToSourceWithHygiene for $t { @@ -262,7 +262,7 @@ pub mod rt { impl ToSource for $t { fn to_source(&self) -> String { let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag)); - pprust::lit_to_string(&dummy_spanned(lit)) + pprust::lit_to_string(&dummy_spanned(lit)).into_owned() } } impl ToSourceWithHygiene for $t { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index af16e19c9f034..e5e67f66529f4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -30,6 +30,7 @@ use ptr::P; use std_inject; use std::{ascii, mem}; +use std::borrow::{Cow, IntoCow}; use std::old_io::{self, IoResult}; use std::iter; @@ -45,6 +46,9 @@ pub enum AnnNode<'a> { pub trait PpAnn { fn pre(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } + fn literal_to_string<'a>(&self, state: &mut State, lit: &'a ast::Lit) -> Cow<'a, str> { + state.literal_to_string(lit) + } } #[derive(Copy)] @@ -309,6 +313,73 @@ pub fn token_to_string(tok: &Token) -> String { } } +fn string_lit_to_string(st: &str, style: ast::StrStyle) -> String { + match style { + ast::CookedStr => { + format!("\"{}\"", st.escape_default()) + } + ast::RawStr(n) => { + format!("r{delim}\"{string}\"{delim}", + delim=repeat("#", n), + string=st) + } + } +} + +pub fn lit_to_string<'a>(lit: &'a ast::Lit) -> Cow<'a, str> { + match lit.node { + ast::LitStr(ref st, style) => { + string_lit_to_string(&st, style).into_cow() + } + ast::LitByte(byte) => { + let mut res = String::from_str("b'"); + res.extend(ascii::escape_default(byte).map(|c| c as char)); + res.push('\''); + res.into_cow() + } + ast::LitChar(ch) => { + let mut res = String::from_str("'"); + res.extend(ch.escape_default()); + res.push('\''); + res.into_cow() + } + ast::LitInt(i, t) => { + match t { + ast::SignedIntLit(st, ast::Plus) => { + ast_util::int_ty_to_string(st, Some(i as i64)) + } + ast::SignedIntLit(st, ast::Minus) => { + let istr = ast_util::int_ty_to_string(st, Some(-(i as i64))); + format!("-{}", istr) + } + ast::UnsignedIntLit(ut) => { + ast_util::uint_ty_to_string(ut, Some(i)) + } + ast::UnsuffixedIntLit(ast::Plus) => { + format!("{}", i) + } + ast::UnsuffixedIntLit(ast::Minus) => { + format!("-{}", i) + } + }.into_cow() + } + ast::LitFloat(ref f, t) => { + format!("{}{}", f, &ast_util::float_ty_to_string(t)).into_cow() + } + ast::LitFloatUnsuffixed(ref f) => f.into_cow(), + ast::LitBool(val) => { + if val { "true" } else { "false" }.into_cow() + } + ast::LitBinary(ref v) => { + let mut escaped: String = String::new(); + for &ch in &**v { + escaped.extend(ascii::escape_default(ch as u8).map(|c| c as char)); + } + format!("b\"{}\"", escaped).into_cow() + } + } +} + // FIXME (Issue #16472): the thing_to_string_impls macro should go away // after we revise the syntax::ext::quote::ToToken impls to go directly // to token-trees instead of thing -> string -> token-trees. @@ -409,10 +480,6 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { $to_string(|s| s.print_attribute(attr)) } -pub fn lit_to_string(l: &ast::Lit) -> String { - $to_string(|s| s.print_literal(l)) -} - pub fn explicit_self_to_string(explicit_self: &ast::ExplicitSelf_) -> String { $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {})) } @@ -1710,7 +1777,8 @@ impl<'a> State<'a> { try!(self.print_expr_addr_of(m, &**expr)); } ast::ExprLit(ref lit) => { - try!(self.print_literal(&**lit)); + let s = self.ann.literal_to_string(self, lit); + try!(word(&mut self.s, &s)); } ast::ExprCast(ref expr, ref ty) => { try!(self.print_expr(&**expr)); @@ -2582,7 +2650,8 @@ impl<'a> State<'a> { ast::MetaNameValue(ref name, ref value) => { try!(self.word_space(&name[..])); try!(self.word_space("=")); - try!(self.print_literal(value)); + let s = self.literal_to_string(value); + try!(word(&mut self.s, &s)); } ast::MetaList(ref name, ref items) => { try!(word(&mut self.s, &name)); @@ -2767,69 +2836,11 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_literal(&mut self, lit: &ast::Lit) -> IoResult<()> { - try!(self.maybe_print_comment(lit.span.lo)); - match self.next_lit(lit.span.lo) { - Some(ref ltrl) => { - return word(&mut self.s, &(*ltrl).lit); - } - _ => () - } - match lit.node { - ast::LitStr(ref st, style) => self.print_string(&st, style), - ast::LitByte(byte) => { - let mut res = String::from_str("b'"); - res.extend(ascii::escape_default(byte).map(|c| c as char)); - res.push('\''); - word(&mut self.s, &res[..]) - } - ast::LitChar(ch) => { - let mut res = String::from_str("'"); - res.extend(ch.escape_default()); - res.push('\''); - word(&mut self.s, &res[..]) - } - ast::LitInt(i, t) => { - match t { - ast::SignedIntLit(st, ast::Plus) => { - word(&mut self.s, - &ast_util::int_ty_to_string(st, Some(i as i64))) - } - ast::SignedIntLit(st, ast::Minus) => { - let istr = ast_util::int_ty_to_string(st, Some(-(i as i64))); - word(&mut self.s, - &format!("-{}", istr)) - } - ast::UnsignedIntLit(ut) => { - word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i))) - } - ast::UnsuffixedIntLit(ast::Plus) => { - word(&mut self.s, &format!("{}", i)) - } - ast::UnsuffixedIntLit(ast::Minus) => { - word(&mut self.s, &format!("-{}", i)) - } - } - } - ast::LitFloat(ref f, t) => { - word(&mut self.s, - &format!( - "{}{}", - &f, - &ast_util::float_ty_to_string(t))) - } - ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]), - ast::LitBool(val) => { - if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") } - } - ast::LitBinary(ref v) => { - let mut escaped: String = String::new(); - for &ch in &**v { - escaped.extend(ascii::escape_default(ch as u8) - .map(|c| c as char)); - } - word(&mut self.s, &format!("b\"{}\"", escaped)) - } + pub fn literal_to_string<'b>(&mut self, lit: &'b ast::Lit) -> Cow<'b, str> { + if let Some(ltrl) = self.next_lit(lit.span.lo) { + ltrl.lit.into_cow() + } else { + lit_to_string(lit) } } @@ -2916,17 +2927,7 @@ impl<'a> State<'a> { pub fn print_string(&mut self, st: &str, style: ast::StrStyle) -> IoResult<()> { - let st = match style { - ast::CookedStr => { - (format!("\"{}\"", st.escape_default())) - } - ast::RawStr(n) => { - (format!("r{delim}\"{string}\"{delim}", - delim=repeat("#", n), - string=st)) - } - }; - word(&mut self.s, &st[..]) + word(&mut self.s, &string_lit_to_string(st, style)) } pub fn next_comment(&mut self) -> Option { diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 83ee2bd08f4ad..b993ccd6d1a9e 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -20,18 +20,18 @@ // #4264 fixed-length vector types -pub fn foo(_: [i32; (3 as usize)]) { } +pub fn foo(_: [i32; (3: usize)]) { } pub fn bar() { - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); + const FOO: usize = ((5: usize) - (4: usize): usize); + let _: [(); (FOO: usize)] = ([((): ())]: [(); 1]); - let _: [(); (1usize as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1usize: usize)] = ([((): ())]: [(); 1]); let _ = - (((&((([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]) - as &[i32; 3]) as *const _ as *const [i32; 3]) as - *const [i32; (3usize as usize)] as *const [i32; 3]); + (((&((([(1: i32), (2: i32), (3: i32)]: [i32; 3])): [i32; 3]): + &[i32; 3]) as *const _: *const [i32; 3]) as + *const [i32; (3usize: usize)]: *const [i32; 3]); @@ -41,56 +41,44 @@ - ((::std::fmt::format as - fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1 - as + ((::std::fmt::format: + fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1: fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new_v1})(({ static __STATIC_FMTSTR: &'static [&'static str] = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) - as + (&([("test": + &'static str)]: + [&'static str; 1]): &'static [&'static str; 1]); - (__STATIC_FMTSTR - as + (__STATIC_FMTSTR: &'static [&'static str]) - } - as + }: &[&str]), - (&(match (() - as + (&(match ((): ()) { () => - ([] - as + ([]: [core::fmt::ArgumentV1<'_>; 0]), - } - as - [core::fmt::ArgumentV1<'_>; 0]) - as - &[core::fmt::ArgumentV1<'_>; 0])) - as - core::fmt::Arguments<'_>)) - as collections::string::String); + }: + [core::fmt::ArgumentV1<'_>; 0]): + &[core::fmt::ArgumentV1<'_>; 0])): + core::fmt::Arguments<'_>)): + collections::string::String); } -pub type Foo = [i32; (3 as usize)]; +pub type Foo = [i32; (3: usize)]; pub struct Bar { - pub x: [i32; (3 as usize)], + pub x: [i32; (3: usize)], } -pub struct TupleBar([i32; (4 as usize)]); -pub enum Baz { BazVariant([i32; (5 as usize)]), } -pub fn id(x: T) -> T { (x as T) } +pub struct TupleBar([i32; (4: usize)]); +pub enum Baz { BazVariant([i32; (5: usize)]), } +pub fn id(x: T) -> T { (x: T) } pub fn use_id() { let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id})(([(1 as i32), (2 as i32), - (3 as i32)] as [i32; 3])) as - [i32; 3]); + ((id::<[i32; (3: usize)]>: + fn([i32; 3]) -> [i32; 3] {id})(([(1: i32), (2: i32), (3: i32)]: + [i32; 3])): [i32; 3]); } fn main() { }