Auto merge of #31206 - nrc:early-save, r=nikomatsakis

r? @nikomatsakis
This commit is contained in:
bors 2016-01-27 10:17:55 +00:00
commit b8b18aac12
8 changed files with 308 additions and 242 deletions

View File

@ -176,15 +176,28 @@ impl Session {
pub fn abort_if_errors(&self) { pub fn abort_if_errors(&self) {
self.diagnostic().abort_if_errors(); self.diagnostic().abort_if_errors();
} }
pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
where F: FnOnce() -> T
{
let mut count = self.err_count();
let result = f();
count -= self.err_count();
if count == 0 {
Ok(result)
} else {
Err(count)
}
}
pub fn abort_if_new_errors<F, T>(&self, f: F) -> T pub fn abort_if_new_errors<F, T>(&self, f: F) -> T
where F: FnOnce() -> T where F: FnOnce() -> T
{ {
let count = self.err_count(); match self.track_errors(f) {
let result = f(); Ok(result) => result,
if self.err_count() > count { Err(_) => {
self.abort_if_errors(); self.abort_if_errors();
unreachable!();
}
} }
result
} }
pub fn span_warn(&self, sp: Span, msg: &str) { pub fn span_warn(&self, sp: Span, msg: &str) {
self.diagnostic().span_warn(sp, msg) self.diagnostic().span_warn(sp, msg)

View File

@ -35,7 +35,7 @@ use rustc_plugin as plugin;
use rustc_front::hir; use rustc_front::hir;
use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion}; use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
use super::Compilation; use super::{Compilation, CompileResult, compile_result_from_err_count};
use serialize::json; use serialize::json;
@ -57,45 +57,50 @@ use syntax::visit;
use syntax; use syntax;
use syntax_ext; use syntax_ext;
pub fn compile_input(sess: Session, macro_rules! throw_if_errors {
($tsess: expr) => {{
let err_count = $tsess.err_count();
if err_count > 0 {
return Err(err_count);
}
}}
}
pub fn compile_input(sess: &Session,
cstore: &CStore, cstore: &CStore,
cfg: ast::CrateConfig, cfg: ast::CrateConfig,
input: &Input, input: &Input,
outdir: &Option<PathBuf>, outdir: &Option<PathBuf>,
output: &Option<PathBuf>, output: &Option<PathBuf>,
addl_plugins: Option<Vec<String>>, addl_plugins: Option<Vec<String>>,
control: CompileController) { control: CompileController) -> CompileResult {
macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: expr) => ({ macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: expr) => ({
let state = $make_state; let state = $make_state;
(control.$point.callback)(state); (control.$point.callback)(state);
if control.$point.stop == Compilation::Stop { if control.$point.stop == Compilation::Stop {
$tsess.abort_if_errors(); return compile_result_from_err_count($tsess.err_count());
return;
} }
})} })}
// We need nested scopes here, because the intermediate results can keep // We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as // large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low // possible to keep the peak memory usage low
let result = { let (outputs, trans) = {
let (outputs, expanded_crate, id) = { let (outputs, expanded_crate, id) = {
let krate = phase_1_parse_input(&sess, cfg, input); let krate = phase_1_parse_input(sess, cfg, input);
controller_entry_point!(after_parse, controller_entry_point!(after_parse,
sess, sess,
CompileState::state_after_parse(input, &sess, outdir, &krate)); CompileState::state_after_parse(input, sess, outdir, &krate));
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, &sess); let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
let id = link::find_crate_name(Some(&sess), &krate.attrs, input); let id = link::find_crate_name(Some(sess), &krate.attrs, input);
let expanded_crate = match phase_2_configure_and_expand(&sess, let expanded_crate = try!(phase_2_configure_and_expand(sess,
&cstore, &cstore,
krate, krate,
&id[..], &id[..],
addl_plugins) { addl_plugins));
None => return,
Some(k) => k,
};
(outputs, expanded_crate, id) (outputs, expanded_crate, id)
}; };
@ -103,14 +108,14 @@ pub fn compile_input(sess: Session,
controller_entry_point!(after_expand, controller_entry_point!(after_expand,
sess, sess,
CompileState::state_after_expand(input, CompileState::state_after_expand(input,
&sess, sess,
outdir, outdir,
&expanded_crate, &expanded_crate,
&id[..])); &id[..]));
let expanded_crate = assign_node_ids(&sess, expanded_crate); let expanded_crate = assign_node_ids(sess, expanded_crate);
// Lower ast -> hir. // Lower ast -> hir.
let lcx = LoweringContext::new(&sess, Some(&expanded_crate)); let lcx = LoweringContext::new(sess, Some(&expanded_crate));
let mut hir_forest = time(sess.time_passes(), let mut hir_forest = time(sess.time_passes(),
"lowering ast -> hir", "lowering ast -> hir",
|| hir_map::Forest::new(lower_crate(&lcx, &expanded_crate))); || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate)));
@ -122,14 +127,14 @@ pub fn compile_input(sess: Session,
} }
let arenas = ty::CtxtArenas::new(); let arenas = ty::CtxtArenas::new();
let hir_map = make_map(&sess, &mut hir_forest); let hir_map = make_map(sess, &mut hir_forest);
write_out_deps(&sess, &outputs, &id); write_out_deps(sess, &outputs, &id);
controller_entry_point!(after_write_deps, controller_entry_point!(after_write_deps,
sess, sess,
CompileState::state_after_write_deps(input, CompileState::state_after_write_deps(input,
&sess, sess,
outdir, outdir,
&hir_map, &hir_map,
&expanded_crate, &expanded_crate,
@ -138,12 +143,12 @@ pub fn compile_input(sess: Session,
&lcx)); &lcx));
time(sess.time_passes(), "attribute checking", || { time(sess.time_passes(), "attribute checking", || {
front::check_attr::check_crate(&sess, &expanded_crate); front::check_attr::check_crate(sess, &expanded_crate);
}); });
time(sess.time_passes(), time(sess.time_passes(),
"early lint checks", "early lint checks",
|| lint::check_ast_crate(&sess, &expanded_crate)); || lint::check_ast_crate(sess, &expanded_crate));
let opt_crate = if sess.opts.debugging_opts.keep_ast || let opt_crate = if sess.opts.debugging_opts.keep_ast ||
sess.opts.debugging_opts.save_analysis { sess.opts.debugging_opts.save_analysis {
@ -153,67 +158,62 @@ pub fn compile_input(sess: Session,
None None
}; };
phase_3_run_analysis_passes(&sess, try!(try!(phase_3_run_analysis_passes(sess,
&cstore, &cstore,
hir_map, hir_map,
&arenas, &arenas,
&id, &id,
control.make_glob_map, control.make_glob_map,
|tcx, mir_map, analysis| { |tcx, mir_map, analysis| {
{
let state =
CompileState::state_after_analysis(input,
&tcx.sess,
outdir,
opt_crate,
tcx.map.krate(),
&analysis,
&mir_map,
tcx,
&lcx,
&id);
(control.after_analysis.callback)(state);
{ throw_if_errors!(tcx.sess);
let state = if control.after_analysis.stop == Compilation::Stop {
CompileState::state_after_analysis(input, return Err(0usize);
&tcx.sess, }
outdir, }
opt_crate,
tcx.map.krate(),
&analysis,
&mir_map,
tcx,
&lcx,
&id);
(control.after_analysis.callback)(state);
tcx.sess.abort_if_errors(); if log_enabled!(::log::INFO) {
if control.after_analysis.stop == Compilation::Stop { println!("Pre-trans");
return Err(()); tcx.print_debug_stats();
} }
} let trans = phase_4_translate_to_llvm(tcx,
mir_map,
analysis);
if log_enabled!(::log::INFO) { if log_enabled!(::log::INFO) {
println!("Pre-trans"); println!("Post-trans");
tcx.print_debug_stats(); tcx.print_debug_stats();
} }
let trans = phase_4_translate_to_llvm(tcx,
mir_map,
analysis);
if log_enabled!(::log::INFO) { // Discard interned strings as they are no longer required.
println!("Post-trans"); token::get_ident_interner().clear();
tcx.print_debug_stats();
}
// Discard interned strings as they are no longer required. Ok((outputs, trans))
token::get_ident_interner().clear(); })))
Ok((outputs, trans))
})
}; };
let (outputs, trans) = if let Ok(out) = result { try!(phase_5_run_llvm_passes(sess, &trans, &outputs));
out
} else {
return;
};
phase_5_run_llvm_passes(&sess, &trans, &outputs);
controller_entry_point!(after_llvm, controller_entry_point!(after_llvm,
sess, sess,
CompileState::state_after_llvm(input, &sess, outdir, &trans)); CompileState::state_after_llvm(input, sess, outdir, &trans));
phase_6_link_output(&sess, &trans, &outputs); phase_6_link_output(sess, &trans, &outputs);
Ok(())
} }
/// The name used for source code that doesn't originate in a file /// The name used for source code that doesn't originate in a file
@ -457,7 +457,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
mut krate: ast::Crate, mut krate: ast::Crate,
crate_name: &str, crate_name: &str,
addl_plugins: Option<Vec<String>>) addl_plugins: Option<Vec<String>>)
-> Option<ast::Crate> { -> Result<ast::Crate, usize> {
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
// strip before anything else because crate metadata may use #[cfg_attr] // strip before anything else because crate metadata may use #[cfg_attr]
@ -469,13 +469,13 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// baz! should not use this definition unless foo is enabled. // baz! should not use this definition unless foo is enabled.
let mut feature_gated_cfgs = vec![]; let mut feature_gated_cfgs = vec![];
krate = time(time_passes, "configuration 1", || { krate = try!(time(time_passes, "configuration 1", || {
sess.abort_if_new_errors(|| { sess.track_errors(|| {
syntax::config::strip_unconfigured_items(sess.diagnostic(), syntax::config::strip_unconfigured_items(sess.diagnostic(),
krate, krate,
&mut feature_gated_cfgs) &mut feature_gated_cfgs)
}) })
}); }));
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
*sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs); *sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs);
@ -484,8 +484,8 @@ pub fn phase_2_configure_and_expand(sess: &Session,
middle::recursion_limit::update_recursion_limit(sess, &krate); middle::recursion_limit::update_recursion_limit(sess, &krate);
}); });
time(time_passes, "gated macro checking", || { try!(time(time_passes, "gated macro checking", || {
sess.abort_if_new_errors(|| { sess.track_errors(|| {
let features = let features =
syntax::feature_gate::check_crate_macros(sess.codemap(), syntax::feature_gate::check_crate_macros(sess.codemap(),
&sess.parse_sess.span_diagnostic, &sess.parse_sess.span_diagnostic,
@ -493,8 +493,8 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// these need to be set "early" so that expansion sees `quote` if enabled. // these need to be set "early" so that expansion sees `quote` if enabled.
*sess.features.borrow_mut() = features; *sess.features.borrow_mut() = features;
}); })
}); }));
krate = time(time_passes, "crate injection", || { krate = time(time_passes, "crate injection", || {
@ -531,7 +531,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
llvm_passes, attributes, .. } = registry; llvm_passes, attributes, .. } = registry;
sess.abort_if_new_errors(|| { try!(sess.track_errors(|| {
let mut ls = sess.lint_store.borrow_mut(); let mut ls = sess.lint_store.borrow_mut();
for pass in early_lint_passes { for pass in early_lint_passes {
ls.register_early_pass(Some(sess), true, pass); ls.register_early_pass(Some(sess), true, pass);
@ -546,14 +546,14 @@ pub fn phase_2_configure_and_expand(sess: &Session,
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
*sess.plugin_attributes.borrow_mut() = attributes.clone(); *sess.plugin_attributes.borrow_mut() = attributes.clone();
}); }));
// Lint plugins are registered; now we can process command line flags. // Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints { if sess.opts.describe_lints {
super::describe_lints(&*sess.lint_store.borrow(), true); super::describe_lints(&*sess.lint_store.borrow(), true);
return None; return Err(0);
} }
sess.abort_if_new_errors(|| sess.lint_store.borrow_mut().process_command_line(sess)); try!(sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess)));
krate = time(time_passes, "expansion", || { krate = time(time_passes, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their // Windows dlls do not have rpaths, so they don't know how to find their
@ -596,21 +596,21 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// of macro expansion. This runs before #[cfg] to try to catch as // of macro expansion. This runs before #[cfg] to try to catch as
// much as possible (e.g. help the programmer avoid platform // much as possible (e.g. help the programmer avoid platform
// specific differences) // specific differences)
time(time_passes, "complete gated feature checking 1", || { try!(time(time_passes, "complete gated feature checking 1", || {
sess.abort_if_new_errors(|| { sess.track_errors(|| {
let features = syntax::feature_gate::check_crate(sess.codemap(), let features = syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic, &sess.parse_sess.span_diagnostic,
&krate, &krate,
&attributes, &attributes,
sess.opts.unstable_features); sess.opts.unstable_features);
*sess.features.borrow_mut() = features; *sess.features.borrow_mut() = features;
}); })
}); }));
// JBC: make CFG processing part of expansion to avoid this problem: // JBC: make CFG processing part of expansion to avoid this problem:
// strip again, in case expansion added anything with a #[cfg]. // strip again, in case expansion added anything with a #[cfg].
krate = sess.abort_if_new_errors(|| { krate = try!(sess.track_errors(|| {
let krate = time(time_passes, "configuration 2", || { let krate = time(time_passes, "configuration 2", || {
syntax::config::strip_unconfigured_items(sess.diagnostic(), syntax::config::strip_unconfigured_items(sess.diagnostic(),
krate, krate,
@ -627,7 +627,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
}); });
krate krate
}); }));
krate = time(time_passes, "maybe building test harness", || { krate = time(time_passes, "maybe building test harness", || {
syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic()) syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic())
@ -648,16 +648,16 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// One final feature gating of the true AST that gets compiled // One final feature gating of the true AST that gets compiled
// later, to make sure we've got everything (e.g. configuration // later, to make sure we've got everything (e.g. configuration
// can insert new attributes via `cfg_attr`) // can insert new attributes via `cfg_attr`)
time(time_passes, "complete gated feature checking 2", || { try!(time(time_passes, "complete gated feature checking 2", || {
sess.abort_if_new_errors(|| { sess.track_errors(|| {
let features = syntax::feature_gate::check_crate(sess.codemap(), let features = syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic, &sess.parse_sess.span_diagnostic,
&krate, &krate,
&attributes, &attributes,
sess.opts.unstable_features); sess.opts.unstable_features);
*sess.features.borrow_mut() = features; *sess.features.borrow_mut() = features;
}); })
}); }));
time(time_passes, time(time_passes,
"const fn bodies and arguments", "const fn bodies and arguments",
@ -667,7 +667,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
println!("Post-expansion node count: {}", count_nodes(&krate)); println!("Post-expansion node count: {}", count_nodes(&krate));
} }
Some(krate) Ok(krate)
} }
pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate { pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
@ -712,7 +712,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
name: &str, name: &str,
make_glob_map: resolve::MakeGlobMap, make_glob_map: resolve::MakeGlobMap,
f: F) f: F)
-> R -> Result<R, usize>
where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R
{ {
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
@ -722,11 +722,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
"external crate/lib resolution", "external crate/lib resolution",
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate)); || LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate));
let lang_items = time(time_passes, "language item collection", || { let lang_items = try!(time(time_passes, "language item collection", || {
sess.abort_if_new_errors(|| { sess.track_errors(|| {
middle::lang_items::collect_language_items(&sess, &hir_map) middle::lang_items::collect_language_items(&sess, &hir_map)
}) })
}); }));
let resolve::CrateMap { let resolve::CrateMap {
def_map, def_map,
@ -773,98 +773,98 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
lang_items, lang_items,
stability::Index::new(krate), stability::Index::new(krate),
|tcx| { |tcx| {
// passes are timed inside typeck // passes are timed inside typeck
typeck::check_crate(tcx, trait_map); typeck::check_crate(tcx, trait_map);
time(time_passes, time(time_passes,
"const checking", "const checking",
|| consts::check_crate(tcx)); || consts::check_crate(tcx));
let access_levels = let access_levels =
time(time_passes, "privacy checking", || { time(time_passes, "privacy checking", || {
rustc_privacy::check_crate(tcx, rustc_privacy::check_crate(tcx,
&export_map, &export_map,
external_exports) external_exports)
}); });
// Do not move this check past lint // Do not move this check past lint
time(time_passes, "stability index", || { time(time_passes, "stability index", || {
tcx.stability.borrow_mut().build(tcx, krate, &access_levels) tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
}); });
time(time_passes, time(time_passes,
"intrinsic checking", "intrinsic checking",
|| middle::intrinsicck::check_crate(tcx)); || middle::intrinsicck::check_crate(tcx));
time(time_passes, time(time_passes,
"effect checking", "effect checking",
|| middle::effect::check_crate(tcx)); || middle::effect::check_crate(tcx));
time(time_passes, time(time_passes,
"match checking", "match checking",
|| middle::check_match::check_crate(tcx)); || middle::check_match::check_crate(tcx));
let mir_map = let mir_map =
time(time_passes, time(time_passes,
"MIR dump", "MIR dump",
|| mir::mir_map::build_mir_for_crate(tcx)); || mir::mir_map::build_mir_for_crate(tcx));
time(time_passes, time(time_passes,
"liveness checking", "liveness checking",
|| middle::liveness::check_crate(tcx)); || middle::liveness::check_crate(tcx));
time(time_passes, time(time_passes,
"borrow checking", "borrow checking",
|| borrowck::check_crate(tcx)); || borrowck::check_crate(tcx));
time(time_passes, time(time_passes,
"rvalue checking", "rvalue checking",
|| rvalues::check_crate(tcx)); || rvalues::check_crate(tcx));
// Avoid overwhelming user with errors if type checking failed. // Avoid overwhelming user with errors if type checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids // I'm not sure how helpful this is, to be honest, but it avoids
// a // a
// lot of annoying errors in the compile-fail tests (basically, // lot of annoying errors in the compile-fail tests (basically,
// lint warnings and so on -- kindck used to do this abort, but // lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis // kindck is gone now). -nmatsakis
tcx.sess.abort_if_errors(); throw_if_errors!(tcx.sess);
let reachable_map = let reachable_map =
time(time_passes, time(time_passes,
"reachability checking", "reachability checking",
|| reachable::find_reachable(tcx, &access_levels)); || reachable::find_reachable(tcx, &access_levels));
time(time_passes, "death checking", || { time(time_passes, "death checking", || {
middle::dead::check_crate(tcx, &access_levels); middle::dead::check_crate(tcx, &access_levels);
}); });
let ref lib_features_used = let ref lib_features_used =
time(time_passes, time(time_passes,
"stability checking", "stability checking",
|| stability::check_unstable_api_usage(tcx)); || stability::check_unstable_api_usage(tcx));
time(time_passes, "unused lib feature checking", || { time(time_passes, "unused lib feature checking", || {
stability::check_unused_or_stable_features(&tcx.sess, stability::check_unused_or_stable_features(&tcx.sess,
lib_features_used) lib_features_used)
}); });
time(time_passes, time(time_passes,
"lint checking", "lint checking",
|| lint::check_crate(tcx, &access_levels)); || lint::check_crate(tcx, &access_levels));
// The above three passes generate errors w/o aborting // The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors(); throw_if_errors!(tcx.sess);
f(tcx, Ok(f(tcx,
mir_map, mir_map,
ty::CrateAnalysis { ty::CrateAnalysis {
export_map: export_map, export_map: export_map,
access_levels: access_levels, access_levels: access_levels,
reachable: reachable_map, reachable: reachable_map,
name: name, name: name,
glob_map: glob_map, glob_map: glob_map,
}) }))
}) })
} }
/// Run the translation phase to LLVM, after which the AST and analysis can /// Run the translation phase to LLVM, after which the AST and analysis can
@ -893,7 +893,7 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
/// as a side effect. /// as a side effect.
pub fn phase_5_run_llvm_passes(sess: &Session, pub fn phase_5_run_llvm_passes(sess: &Session,
trans: &trans::CrateTranslation, trans: &trans::CrateTranslation,
outputs: &OutputFilenames) { outputs: &OutputFilenames) -> CompileResult {
if sess.opts.cg.no_integrated_as { if sess.opts.cg.no_integrated_as {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(OutputType::Assembly, None); map.insert(OutputType::Assembly, None);
@ -913,7 +913,8 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
|| write::run_passes(sess, trans, &sess.opts.output_types, outputs)); || write::run_passes(sess, trans, &sess.opts.output_types, outputs));
} }
sess.abort_if_errors(); throw_if_errors!(sess);
Ok(())
} }
/// Run the linker on any artifacts that resulted from the LLVM run. /// Run the linker on any artifacts that resulted from the LLVM run.

View File

@ -105,49 +105,95 @@ pub mod target_features;
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
md#bug-reports"; md#bug-reports";
// Err(0) means compilation was stopped, but no errors were found.
// This would be better as a dedicated enum, but using try! is so convenient.
pub type CompileResult = Result<(), usize>;
pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
if err_count == 0 {
Ok(())
} else {
Err(err_count)
}
}
#[inline]
fn abort_msg(err_count: usize) -> String {
match err_count {
0 => "aborting with no errors (maybe a bug?)".to_owned(),
1 => "aborting due to previous error".to_owned(),
e => format!("aborting due to {} previous errors", e),
}
}
pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
match result {
Err(err_count) => {
sess.fatal(&abort_msg(err_count));
}
Ok(x) => x,
}
}
pub fn run(args: Vec<String>) -> isize { pub fn run(args: Vec<String>) -> isize {
monitor(move || run_compiler(&args, &mut RustcDefaultCalls)); monitor(move || {
let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
if let Err(err_count) = result {
if err_count > 0 {
match session {
Some(sess) => sess.fatal(&abort_msg(err_count)),
None => {
let mut emitter =
errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal);
panic!(errors::FatalError);
}
}
}
}
});
0 0
} }
// Parse args and run the compiler. This is the primary entry point for rustc. // Parse args and run the compiler. This is the primary entry point for rustc.
// See comments on CompilerCalls below for details about the callbacks argument. // See comments on CompilerCalls below for details about the callbacks argument.
pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>) { pub fn run_compiler<'a>(args: &[String],
macro_rules! do_or_return {($expr: expr) => { callbacks: &mut CompilerCalls<'a>)
-> (CompileResult, Option<Session>) {
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
match $expr { match $expr {
Compilation::Stop => return, Compilation::Stop => return (Ok(()), $sess),
Compilation::Continue => {} Compilation::Continue => {}
} }
}} }}
let matches = match handle_options(args.to_vec()) { let matches = match handle_options(args.to_vec()) {
Some(matches) => matches, Some(matches) => matches,
None => return, None => return (Ok(()), None),
}; };
let sopts = config::build_session_options(&matches); let sopts = config::build_session_options(&matches);
let descriptions = diagnostics_registry(); let descriptions = diagnostics_registry();
do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.error_format)); do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.error_format), None);
let (odir, ofile) = make_output(&matches); let (odir, ofile) = make_output(&matches);
let (input, input_file_path) = match make_input(&matches.free) { let (input, input_file_path) = match make_input(&matches.free) {
Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) { None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) {
Some((input, input_file_path)) => (input, input_file_path), Some((input, input_file_path)) => (input, input_file_path),
None => return, None => return (Ok(()), None),
}, },
}; };
let cstore = Rc::new(CStore::new(token::get_ident_interner())); let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = build_session(sopts, input_file_path, descriptions, let sess = build_session(sopts, input_file_path, descriptions, cstore.clone());
cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess); let mut cfg = config::build_configuration(&sess);
target_features::add_configuration(&mut cfg, &sess); target_features::add_configuration(&mut cfg, &sess);
do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess));
// It is somewhat unfortunate that this is hardwired in - this is forced by // It is somewhat unfortunate that this is hardwired in - this is forced by
// the fact that pretty_print_input requires the session by value. // the fact that pretty_print_input requires the session by value.
@ -155,7 +201,7 @@ pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>) {
match pretty { match pretty {
Some((ppm, opt_uii)) => { Some((ppm, opt_uii)) => {
pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile); pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile);
return; return (Ok(()), None);
} }
None => { None => {
// continue // continue
@ -164,8 +210,9 @@ pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>) {
let plugins = sess.opts.debugging_opts.extra_plugins.clone(); let plugins = sess.opts.debugging_opts.extra_plugins.clone();
let control = callbacks.build_controller(&sess); let control = callbacks.build_controller(&sess);
driver::compile_input(sess, &cstore, cfg, &input, &odir, &ofile, (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile,
Some(plugins), control); Some(plugins), control),
Some(sess))
} }
// Extract output directory and file from matches. // Extract output directory and file from matches.

View File

@ -17,7 +17,7 @@ use self::NodesMatchingUII::*;
use rustc_trans::back::link; use rustc_trans::back::link;
use driver; use {driver, abort_on_err};
use rustc::middle::ty; use rustc::middle::ty;
use rustc::middle::cfg; use rustc::middle::cfg;
@ -194,21 +194,21 @@ impl PpSourceMode {
f(&annotation, payload, &ast_map.forest.krate) f(&annotation, payload, &ast_map.forest.krate)
} }
PpmTyped => { PpmTyped => {
driver::phase_3_run_analysis_passes(sess, abort_on_err(driver::phase_3_run_analysis_passes(sess,
cstore, cstore,
ast_map.clone(), ast_map.clone(),
arenas, arenas,
id, id,
resolve::MakeGlobMap::No, resolve::MakeGlobMap::No,
|tcx, _, _| { |tcx, _, _| {
let annotation = TypedAnnotation { let annotation = TypedAnnotation {
tcx: tcx, tcx: tcx,
}; };
let _ignore = tcx.dep_graph.in_ignore(); let _ignore = tcx.dep_graph.in_ignore();
f(&annotation, f(&annotation,
payload, payload,
&ast_map.forest.krate) &ast_map.forest.krate)
}) }), sess)
} }
_ => panic!("Should use call_with_pp_support"), _ => panic!("Should use call_with_pp_support"),
} }
@ -694,8 +694,8 @@ pub fn pretty_print_input(sess: Session,
let compute_ast_map = needs_ast_map(&ppm, &opt_uii); let compute_ast_map = needs_ast_map(&ppm, &opt_uii);
let krate = if compute_ast_map { let krate = if compute_ast_map {
match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) { match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) {
None => return, Err(_) => return,
Some(k) => driver::assign_node_ids(&sess, k), Ok(k) => driver::assign_node_ids(&sess, k),
} }
} else { } else {
krate krate
@ -818,19 +818,19 @@ pub fn pretty_print_input(sess: Session,
match code { match code {
Some(code) => { Some(code) => {
let variants = gather_flowgraph_variants(&sess); let variants = gather_flowgraph_variants(&sess);
driver::phase_3_run_analysis_passes(&sess, abort_on_err(driver::phase_3_run_analysis_passes(&sess,
&cstore, &cstore,
ast_map, ast_map,
&arenas, &arenas,
&id, &id,
resolve::MakeGlobMap::No, resolve::MakeGlobMap::No,
|tcx, _, _| { |tcx, _, _| {
print_flowgraph(variants, print_flowgraph(variants,
tcx, tcx,
code, code,
mode, mode,
out) out)
}) }), &sess)
} }
None => { None => {
let message = format!("--pretty=flowgraph needs block, fn, or method; got \ let message = format!("--pretty=flowgraph needs block, fn, or method; got \

View File

@ -10,7 +10,7 @@
pub use self::MaybeTyped::*; pub use self::MaybeTyped::*;
use rustc_lint; use rustc_lint;
use rustc_driver::{driver, target_features}; use rustc_driver::{driver, target_features, abort_on_err};
use rustc::session::{self, config}; use rustc::session::{self, config};
use rustc::middle::def_id::DefId; use rustc::middle::def_id::DefId;
use rustc::middle::privacy::AccessLevels; use rustc::middle::privacy::AccessLevels;
@ -147,13 +147,13 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
let arenas = ty::CtxtArenas::new(); let arenas = ty::CtxtArenas::new();
let hir_map = driver::make_map(&sess, &mut hir_forest); let hir_map = driver::make_map(&sess, &mut hir_forest);
driver::phase_3_run_analysis_passes(&sess, abort_on_err(driver::phase_3_run_analysis_passes(&sess,
&cstore, &cstore,
hir_map, hir_map,
&arenas, &arenas,
&name, &name,
resolve::MakeGlobMap::No, resolve::MakeGlobMap::No,
|tcx, _, analysis| { |tcx, _, analysis| {
let _ignore = tcx.dep_graph.in_ignore(); let _ignore = tcx.dep_graph.in_ignore();
let ty::CrateAnalysis { access_levels, .. } = analysis; let ty::CrateAnalysis { access_levels, .. } = analysis;
@ -200,5 +200,5 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
*analysis.inlined.borrow_mut() = map; *analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get(); analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis) (krate, analysis)
}) }), &sess)
} }

View File

@ -250,7 +250,12 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
if no_run { if no_run {
control.after_analysis.stop = Compilation::Stop; control.after_analysis.stop = Compilation::Stop;
} }
driver::compile_input(sess, &cstore, cfg, &input, &out, &None, None, control); let result = driver::compile_input(&sess, &cstore, cfg, &input,
&out, &None, None, control);
match result {
Err(count) if count > 0 => sess.fatal("aborting due to previous error(s)"),
_ => {}
}
if no_run { return } if no_run { return }

View File

@ -32,7 +32,7 @@ use rustc::middle::cstore::{CrateStore, LinkagePreference};
use rustc::middle::ty; use rustc::middle::ty;
use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
use rustc::session::build_session; use rustc::session::build_session;
use rustc_driver::driver; use rustc_driver::{driver, abort_on_err};
use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_resolve::MakeGlobMap; use rustc_resolve::MakeGlobMap;
use rustc_metadata::cstore::CStore; use rustc_metadata::cstore::CStore;
@ -234,7 +234,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
let arenas = ty::CtxtArenas::new(); let arenas = ty::CtxtArenas::new();
let ast_map = driver::make_map(&sess, &mut hir_forest); let ast_map = driver::make_map(&sess, &mut hir_forest);
driver::phase_3_run_analysis_passes( abort_on_err(driver::phase_3_run_analysis_passes(
&sess, &cstore, ast_map, &arenas, &id, &sess, &cstore, ast_map, &arenas, &id,
MakeGlobMap::No, |tcx, mir_map, analysis| { MakeGlobMap::No, |tcx, mir_map, analysis| {
@ -254,7 +254,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
let modp = llmod as usize; let modp = llmod as usize;
(modp, deps) (modp, deps)
}) }), &sess)
}).unwrap(); }).unwrap();
match handle.join() { match handle.join() {

View File

@ -65,7 +65,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
let cfg = build_configuration(&sess); let cfg = build_configuration(&sess);
let control = CompileController::basic(); let control = CompileController::basic();
compile_input(sess, &cstore, compile_input(&sess, &cstore,
cfg, cfg,
&Input::Str(code), &Input::Str(code),
&None, &None,