]> git.lizzy.rs Git - rust.git/commitdiff
Make the compilation process more easily customisable
authorNick Cameron <ncameron@mozilla.com>
Sun, 11 Jan 2015 02:03:34 +0000 (15:03 +1300)
committerNick Cameron <ncameron@mozilla.com>
Sun, 11 Jan 2015 23:53:07 +0000 (12:53 +1300)
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_trans/save/mod.rs
src/librustdoc/core.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/test/run-make/issue-19371/foo.rs

index c2af4315b06a2c7bbb80e8c821aec3644bb2edea..f35f8ab1b40f5cb741392bf2cb3b0390b0e1f0aa 100644 (file)
@@ -24,7 +24,6 @@
 use rustc_resolve as resolve;
 use rustc_trans::back::link;
 use rustc_trans::back::write;
-use rustc_trans::save;
 use rustc_trans::trans;
 use rustc_typeck as typeck;
 
@@ -47,23 +46,43 @@ pub fn compile_input(sess: Session,
                      input: &Input,
                      outdir: &Option<Path>,
                      output: &Option<Path>,
-                     addl_plugins: Option<Vec<String>>) {
+                     addl_plugins: Option<Vec<String>>,
+                     control: CompileController) {
+    macro_rules! controller_entry_point{($point: ident, $make_state: expr) => ({
+        {
+            let state = $make_state;
+            (control.$point.callback)(state);
+        }
+        if control.$point.stop {
+            return;
+        }
+    })}
+
     // 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
     // possible to keep the peak memory usage low
     let (outputs, trans, sess) = {
         let (outputs, expanded_crate, id) = {
             let krate = phase_1_parse_input(&sess, cfg, input);
-            if stop_after_phase_1(&sess) { return; }
+
+            controller_entry_point!(after_parse,
+                                    CompileState::state_after_parse(input,
+                                                                    &sess,
+                                                                    outdir,
+                                                                    &krate));
+
             let outputs = build_output_filenames(input,
                                                  outdir,
                                                  output,
                                                  &krate.attrs[],
                                                  &sess);
-            let id = link::find_crate_name(Some(&sess), &krate.attrs[],
+            let id = link::find_crate_name(Some(&sess),
+                                           &krate.attrs[],
                                            input);
             let expanded_crate
-                = match phase_2_configure_and_expand(&sess, krate, &id[],
+                = match phase_2_configure_and_expand(&sess,
+                                                     krate,
+                                                     &id[],
                                                      addl_plugins) {
                     None => return,
                     Some(k) => k
@@ -72,23 +91,37 @@ pub fn compile_input(sess: Session,
             (outputs, expanded_crate, id)
         };
 
+        controller_entry_point!(after_expand,
+                                CompileState::state_after_expand(input,
+                                                                 &sess,
+                                                                 outdir,
+                                                                 &expanded_crate,
+                                                                 &id[]));
+
         let mut forest = ast_map::Forest::new(expanded_crate);
         let ast_map = assign_node_ids_and_map(&sess, &mut forest);
 
         write_out_deps(&sess, input, &outputs, &id[]);
 
-        if stop_after_phase_2(&sess) { return; }
-
         let arenas = ty::CtxtArenas::new();
-        let analysis = phase_3_run_analysis_passes(sess, ast_map, &arenas, id);
-        phase_save_analysis(&analysis.ty_cx.sess, analysis.ty_cx.map.krate(), &analysis, outdir);
+        let analysis = phase_3_run_analysis_passes(sess,
+                                                   ast_map,
+                                                   &arenas,
+                                                   id,
+                                                   control.make_glob_map);
+
+        controller_entry_point!(after_analysis,
+                                CompileState::state_after_analysis(input,
+                                                                   &analysis.ty_cx.sess,
+                                                                   outdir,
+                                                                   analysis.ty_cx.map.krate(),
+                                                                   &analysis,
+                                                                   &analysis.ty_cx));
 
         if log_enabled!(::log::INFO) {
             println!("Pre-trans");
             analysis.ty_cx.print_debug_stats();
         }
-
-        if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
         let (tcx, trans) = phase_4_translate_to_llvm(analysis);
 
         if log_enabled!(::log::INFO) {
@@ -102,7 +135,13 @@ pub fn compile_input(sess: Session,
         (outputs, trans, tcx.sess)
     };
     phase_5_run_llvm_passes(&sess, &trans, &outputs);
-    if stop_after_phase_5(&sess) { return; }
+
+    controller_entry_point!(after_llvm,
+                            CompileState::state_after_llvm(input,
+                                                           &sess,
+                                                           outdir,
+                                                           &trans));
+
     phase_6_link_output(&sess, &trans, &outputs);
 }
 
@@ -120,6 +159,146 @@ pub fn source_name(input: &Input) -> String {
     }
 }
 
+/// CompileController is used to customise compilation, it allows compilation to
+/// be stopped and/or to call arbitrary code at various points in compilation.
+/// It also allows for various flags to be set to influence what information gets
+/// colelcted during compilation.
+///
+/// This is a somewhat higher level controller than a Session - the Session
+/// controls what happens in each phase, whereas the CompileController controls
+/// whether a phase is run at all and whether other code (from outside the
+/// the compiler) is run between phases.
+///
+/// Note that if compilation is set to stop and a callback is provided for a
+/// given entry point, the callback is called before compilation is stopped.
+///
+/// Expect more entry points to be added in the future.
+pub struct CompileController<'a> {
+    pub after_parse: PhaseController<'a>,
+    pub after_expand: PhaseController<'a>,
+    pub after_analysis: PhaseController<'a>,
+    pub after_llvm: PhaseController<'a>,
+
+    pub make_glob_map: resolve::MakeGlobMap,
+}
+
+impl<'a> CompileController<'a> {
+    pub fn basic() -> CompileController<'a> {
+        CompileController {
+            after_parse: PhaseController::basic(),
+            after_expand: PhaseController::basic(),
+            after_analysis: PhaseController::basic(),
+            after_llvm: PhaseController::basic(),
+            make_glob_map: resolve::MakeGlobMap::No,
+        }
+    }
+}
+
+pub struct PhaseController<'a> {
+    pub stop: bool,
+    pub callback: Box<Fn(CompileState) -> () + 'a>,
+}
+
+impl<'a> PhaseController<'a> {
+    pub fn basic() -> PhaseController<'a> {
+        PhaseController {
+            stop: false,
+            callback: box |&: _| {},
+        }
+    }
+}
+
+/// 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 input: &'a Input,
+    pub session: &'a Session,
+    pub cfg: Option<&'a ast::CrateConfig>,
+    pub krate: Option<&'a ast::Crate>,
+    pub crate_name: Option<&'a str>,
+    pub output_filenames: Option<&'a OutputFilenames>,
+    pub out_dir: Option<&'a Path>,
+    pub expanded_crate: Option<&'a ast::Crate>,
+    pub ast_map: Option<&'a ast_map::Map<'ast>>,
+    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> {
+    fn empty(input: &'a Input,
+             session: &'a Session,
+             out_dir: &'a Option<Path>)
+             -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            input: input,
+            session: session,
+            out_dir: out_dir.as_ref(),
+            cfg: None,
+            krate: None,
+            crate_name: None,
+            output_filenames: None,
+            expanded_crate: None,
+            ast_map: None,
+            analysis: None,
+            tcx: None,
+            trans: None,
+        }
+    }
+
+    fn state_after_parse(input: &'a Input,
+                         session: &'a Session,
+                         out_dir: &'a Option<Path>,
+                         krate: &'a ast::Crate)
+                         -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            krate: Some(krate),
+            .. CompileState::empty(input, session, out_dir)
+        }
+    }
+
+    fn state_after_expand(input: &'a Input,
+                          session: &'a Session,
+                          out_dir: &'a Option<Path>,
+                          expanded_crate: &'a ast::Crate,
+                          crate_name: &'a str)
+                          -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            crate_name: Some(crate_name),
+            expanded_crate: Some(expanded_crate),
+            .. CompileState::empty(input, session, out_dir)
+        }
+    }
+
+    fn state_after_analysis(input: &'a Input,
+                            session: &'a Session,
+                            out_dir: &'a Option<Path>,
+                            krate: &'a ast::Crate,
+                            analysis: &'a ty::CrateAnalysis<'tcx>,
+                            tcx: &'a ty::ctxt<'tcx>)
+                            -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            analysis: Some(analysis),
+            tcx: Some(tcx),
+            krate: Some(krate),
+            .. CompileState::empty(input, session, out_dir)
+        }
+    }
+
+
+    fn state_after_llvm(input: &'a Input,
+                        session: &'a Session,
+                        out_dir: &'a Option<Path>,
+                        trans: &'a trans::CrateTranslation)
+                        -> CompileState<'a, 'ast, 'tcx> {
+        CompileState {
+            trans: Some(trans),
+            .. CompileState::empty(input, session, out_dir)
+        }
+    }
+}
+
 pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
     -> ast::Crate {
     // These may be left in an incoherent state after a previous compile.
@@ -347,7 +526,9 @@ fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
 pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
                                          ast_map: ast_map::Map<'tcx>,
                                          arenas: &'tcx ty::CtxtArenas<'tcx>,
-                                         name: String) -> ty::CrateAnalysis<'tcx> {
+                                         name: String,
+                                         make_glob_map: resolve::MakeGlobMap)
+                                         -> ty::CrateAnalysis<'tcx> {
     let time_passes = sess.time_passes();
     let krate = ast_map.krate();
 
@@ -357,11 +538,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     let lang_items = time(time_passes, "language item collection", (), |_|
                           middle::lang_items::collect_language_items(krate, &sess));
 
-    let make_glob_map = if save_analysis(&sess) {
-        resolve::MakeGlobMap::Yes
-    } else {
-        resolve::MakeGlobMap::No
-    };
     let resolve::CrateMap {
         def_map,
         freevars,
@@ -483,21 +659,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     }
 }
 
-fn save_analysis(sess: &Session) -> bool {
-    sess.opts.debugging_opts.save_analysis
-}
-
-pub fn phase_save_analysis(sess: &Session,
-                           krate: &ast::Crate,
-                           analysis: &ty::CrateAnalysis,
-                           odir: &Option<Path>) {
-    if !save_analysis(sess) {
-        return;
-    }
-    time(sess.time_passes(), "save analysis", krate, |krate|
-         save::process_crate(sess, krate, analysis, odir));
-}
-
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
 pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
@@ -559,41 +720,6 @@ pub fn phase_6_link_output(sess: &Session,
     os::setenv("PATH", old_path);
 }
 
-pub fn stop_after_phase_3(sess: &Session) -> bool {
-   if sess.opts.no_trans {
-        debug!("invoked with --no-trans, returning early from compile_input");
-        return true;
-    }
-    return false;
-}
-
-pub fn stop_after_phase_1(sess: &Session) -> bool {
-    if sess.opts.parse_only {
-        debug!("invoked with --parse-only, returning early from compile_input");
-        return true;
-    }
-    if sess.opts.show_span.is_some() {
-        return true;
-    }
-    return sess.opts.debugging_opts.ast_json_noexpand;
-}
-
-pub fn stop_after_phase_2(sess: &Session) -> bool {
-    if sess.opts.no_analysis {
-        debug!("invoked with --no-analysis, returning early from compile_input");
-        return true;
-    }
-    return sess.opts.debugging_opts.ast_json;
-}
-
-pub fn stop_after_phase_5(sess: &Session) -> bool {
-    if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
-        debug!("not building executable, returning early from compile_input");
-        return true;
-    }
-    return false;
-}
-
 fn escape_dep_filename(filename: &str) -> String {
     // Apparently clang and gcc *only* escape spaces:
     // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
index 9122a34a79362db703a50e00742593d09d37f6e5..ce2b03e17448a1398f2b93c34d720b84b2309b40 100644 (file)
 
 pub use syntax::diagnostic;
 
+use driver::CompileController;
+
+use rustc_resolve as resolve;
 use rustc_trans::back::link;
+use rustc_trans::save;
 use rustc::session::{config, Session, build_session};
 use rustc::session::config::{Input, PrintRequest, UnstableFeatures};
 use rustc::lint::Lint;
@@ -56,6 +60,7 @@
 use rustc::metadata;
 use rustc::metadata::creader::CrateOrString::Str;
 use rustc::DIAGNOSTICS;
+use rustc::util::common::time;
 
 use std::cmp::Ordering::Equal;
 use std::io;
@@ -188,7 +193,43 @@ fn run_compiler(args: &[String]) {
     }
 
     let plugins = sess.opts.debugging_opts.extra_plugins.clone();
-    driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins));
+    let control = build_controller(&sess);
+    driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control);
+}
+
+fn build_controller<'a>(sess: &Session) -> CompileController<'a> {
+    let mut control = CompileController::basic();
+
+    if sess.opts.parse_only ||
+       sess.opts.show_span.is_some() ||
+       sess.opts.debugging_opts.ast_json_noexpand {
+        control.after_parse.stop = true;
+    }
+
+    if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
+        control.after_expand.stop = true;
+    }
+
+    if sess.opts.no_trans {
+        control.after_analysis.stop = true;
+    }
+
+    if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
+        control.after_llvm.stop = true;
+    }
+
+    if sess.opts.debugging_opts.save_analysis {
+        control.after_analysis.callback = box |state| {
+            time(state.session.time_passes(), "save analysis", state.krate.unwrap(), |krate|
+                 save::process_crate(state.session,
+                                     krate,
+                                     state.analysis.unwrap(),
+                                     state.out_dir));
+        };
+        control.make_glob_map = resolve::MakeGlobMap::Yes;
+    }
+
+    control
 }
 
 pub fn get_unstable_features_setting() -> UnstableFeatures {
index 1765c80f9437b45b28807545f10e62f8e5f46a7a..6429c5f59856e2394f23cf6ac85a489defb1d003 100644 (file)
@@ -27,6 +27,7 @@
 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};
@@ -133,7 +134,11 @@ fn call_with_pp_support<'tcx, A, B, F>(&self,
             }
             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);
+                let analysis = driver::phase_3_run_analysis_passes(sess,
+                                                                   ast_map,
+                                                                   arenas,
+                                                                   id,
+                                                                   resolve::MakeGlobMap::No);
                 let annotation = TypedAnnotation { analysis: analysis };
                 f(&annotation, payload)
             }
@@ -603,7 +608,11 @@ pub fn pretty_print_input(sess: Session,
             match code {
                 Some(code) => {
                     let variants = gather_flowgraph_variants(&sess);
-                    let analysis = driver::phase_3_run_analysis_passes(sess, ast_map, &arenas, id);
+                    let analysis = driver::phase_3_run_analysis_passes(sess,
+                                                                       ast_map,
+                                                                       &arenas,
+                                                                       id,
+                                                                       resolve::MakeGlobMap::No);
                     print_flowgraph(variants, analysis, code, out)
                 }
                 None => {
index eb163ed7406f25597654631f13b9bfe80fb5fbea..1bd8e01817485732cf82ad4106c17b97b8c70901 100644 (file)
@@ -1505,7 +1505,7 @@ fn visit_local(&mut self, l: &ast::Local) {
 pub fn process_crate(sess: &Session,
                      krate: &ast::Crate,
                      analysis: &ty::CrateAnalysis,
-                     odir: &Option<Path>) {
+                     odir: Option<&Path>) {
     if generated_code(krate.span) {
         return;
     }
@@ -1524,8 +1524,8 @@ pub fn process_crate(sess: &Session,
     // find a path to dump our data to
     let mut root_path = match os::getenv("DXR_RUST_TEMP_FOLDER") {
         Some(val) => Path::new(val),
-        None => match *odir {
-            Some(ref val) => val.join("dxr"),
+        None => match odir {
+            Some(val) => val.join("dxr"),
             None => Path::new("dxr-temp"),
         },
     };
index 4885bd373eb1dfd74e57fa43062be708ec013d0f..5bef0195874b64616b8742ddb929847034a50558 100644 (file)
@@ -16,6 +16,7 @@
 use rustc::middle::{privacy, ty};
 use rustc::lint;
 use rustc_trans::back::link;
+use rustc_resolve as resolve;
 
 use syntax::{ast, ast_map, codemap, diagnostic};
 
@@ -126,7 +127,11 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
     let arenas = ty::CtxtArenas::new();
     let ty::CrateAnalysis {
         exported_items, public_items, ty_cx, ..
-    } = driver::phase_3_run_analysis_passes(sess, ast_map, &arenas, name);
+    } = driver::phase_3_run_analysis_passes(sess,
+                                            ast_map,
+                                            &arenas,
+                                            name,
+                                            resolve::MakeGlobMap::No);
 
     let ctxt = DocContext {
         krate: ty_cx.map.krate(),
index 6d5df3d777d8677f125c09cadb994a0537496003..e6eed4806338bc53c37221ab9ef03c417a6c6fac 100644 (file)
@@ -27,6 +27,7 @@
 extern crate rustc;
 extern crate rustc_trans;
 extern crate rustc_driver;
+extern crate rustc_resolve;
 extern crate serialize;
 extern crate syntax;
 extern crate "test" as testing;
index 38ce73895466567809d7eabc9f462d4edacace83..9b8d220acc394010804fd72461591585a055ec20 100644 (file)
@@ -123,7 +123,6 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
         search_paths: libs,
         crate_types: vec!(config::CrateTypeExecutable),
         output_types: vec!(config::OutputTypeExe),
-        no_trans: no_run,
         externs: externs,
         cg: config::CodegenOptions {
             prefer_dynamic: true,
@@ -170,14 +169,18 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
         diagnostic::mk_span_handler(diagnostic_handler, codemap);
 
     let sess = session::build_session_(sessopts,
-                                      None,
-                                      span_diagnostic_handler);
+                                       None,
+                                       span_diagnostic_handler);
 
     let outdir = TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir");
     let out = Some(outdir.path().clone());
     let cfg = config::build_configuration(&sess);
     let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
-    driver::compile_input(sess, cfg, &input, &out, &None, None);
+    let mut control = driver::CompileController::basic();
+    if no_run {
+        control.after_analysis.stop = true;
+    }
+    driver::compile_input(sess, cfg, &input, &out, &None, None, control);
 
     if no_run { return }
 
index 8a0c14d2d7e366ce41772bc7faf066e4790db19b..fe7df6411599c6a5c8882aaa5e59fb32987cf4a7 100644 (file)
@@ -14,7 +14,7 @@
 
 use rustc::session::{build_session, Session};
 use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe};
-use rustc_driver::driver::{compile_input};
+use rustc_driver::driver::{compile_input, CompileController};
 use syntax::diagnostics::registry::Registry;
 
 fn main() {
@@ -52,11 +52,13 @@ fn basic_sess(sysroot: Path) -> Session {
 fn compile(code: String, output: Path, sysroot: Path) {
     let sess = basic_sess(sysroot);
     let cfg = build_configuration(&sess);
+    let control = CompileController::basic();
 
     compile_input(sess,
             cfg,
             &Input::Str(code),
             &None,
             &Some(output),
-            None);
+            None,
+            control);
 }