about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2013-07-26 23:49:38 -0700
committerGraydon Hoare <graydon@mozilla.com>2013-07-27 00:48:05 -0700
commit413446c85b44a7d9269a0723ed043e16d09e2324 (patch)
tree975fa7d9c2c2e986a2befaa7a411c7474cf24032 /src
parent300ba1cc5cdd4e431981385888afda8c66a34d85 (diff)
rustc: reorganize driver, replace compile_upto with multiple more-obvious functions.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/driver/driver.rs467
-rw-r--r--src/librustc/middle/trans/base.rs28
-rw-r--r--src/librusti/rusti.rs34
-rw-r--r--src/librustpkg/rustpkg.rs11
-rw-r--r--src/librustpkg/util.rs31
5 files changed, 292 insertions, 279 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 278c7c3949e..65b78baba40 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -16,6 +16,8 @@ use driver::session::{Session, Session_, No, Less, Default};
 use driver::session;
 use front;
 use lib::llvm::llvm;
+use lib::llvm::{ContextRef, ModuleRef};
+use metadata::common::LinkMeta;
 use metadata::{creader, cstore, filesearch};
 use metadata;
 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
@@ -23,7 +25,7 @@ use middle;
 use util::common::time;
 use util::ppaux;
 
-use std::hashmap::HashMap;
+use std::hashmap::{HashMap,HashSet};
 use std::int;
 use std::io;
 use std::os;
@@ -132,280 +134,295 @@ pub enum input {
     str_input(@str)
 }
 
-pub fn parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
+pub fn phase_1_parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
     -> @ast::Crate {
-    match *input {
-      file_input(ref file) => {
-        parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
-      }
-      str_input(src) => {
-        parse::parse_crate_from_source_str(
-            anon_src(), src, cfg, sess.parse_sess)
-      }
-    }
-}
-
-/// First phase to do, last phase to do
-#[deriving(Eq)]
-pub struct compile_upto {
-    from: compile_phase,
-    to: compile_phase
-}
-
-#[deriving(Eq)]
-pub enum compile_phase {
-    cu_parse,
-    cu_expand, // means "it's already expanded"
-    cu_typeck,
-    cu_no_trans,
-    cu_everything,
+    time(sess.time_passes(), ~"parsing", || {
+        match *input {
+            file_input(ref file) => {
+                parse::parse_crate_from_file(&(*file), cfg.clone(), sess.parse_sess)
+            }
+            str_input(src) => {
+                parse::parse_crate_from_source_str(
+                    anon_src(), src, cfg.clone(), sess.parse_sess)
+            }
+        }
+    })
 }
 
 // For continuing compilation after a parsed crate has been
 // modified
 
-
-#[fixed_stack_segment]
-pub fn compile_rest(sess: Session,
-                    cfg: ast::CrateConfig,
-                    phases: compile_upto,
-                    outputs: Option<@OutputFilenames>,
-                    curr: Option<@ast::Crate>)
-    -> (Option<@ast::Crate>, Option<ty::ctxt>) {
-
+/// Run the "early phases" of the compiler: initial `cfg` processing,
+/// syntax expansion, secondary `cfg` expansion, synthesis of a test
+/// harness if one is to be provided and injection of a dependency on the
+/// standard library and prelude.
+pub fn phase_2_configure_and_expand(sess: Session,
+                                    cfg: ast::CrateConfig,
+                                    mut crate: @ast::Crate) -> @ast::Crate {
     let time_passes = sess.time_passes();
 
-    let mut crate = curr.unwrap();
-
-    if phases.from == cu_parse || phases.from == cu_everything {
+    *sess.building_library = session::building_library(sess.opts.crate_type,
+                                                       crate, sess.opts.test);
 
-        *sess.building_library = session::building_library(
-            sess.opts.crate_type, crate, sess.opts.test);
 
-        // strip before expansion to allow macros to depend on
-        // configuration variables e.g/ in
-        //
-        //   #[macro_escape] #[cfg(foo)]
-        //   mod bar { macro_rules! baz!(() => {{}}) }
-        //
-        // baz! should not use this definition unless foo is enabled.
-        crate = time(time_passes, ~"std macros injection", ||
-                     syntax::ext::expand::inject_std_macros(sess.parse_sess,
-                                                            cfg.clone(),
-                                                            crate));
+    // strip before expansion to allow macros to depend on
+    // configuration variables e.g/ in
+    //
+    //   #[macro_escape] #[cfg(foo)]
+    //   mod bar { macro_rules! baz!(() => {{}}) }
+    //
+    // baz! should not use this definition unless foo is enabled.
+    crate = time(time_passes, ~"std macros injection", ||
+                 syntax::ext::expand::inject_std_macros(sess.parse_sess,
+                                                        cfg.clone(),
+                                                        crate));
 
-        crate = time(time_passes, ~"configuration 1", ||
-                     front::config::strip_unconfigured_items(crate));
+    crate = time(time_passes, ~"configuration 1", ||
+                 front::config::strip_unconfigured_items(crate));
 
-        crate = time(time_passes, ~"expansion", ||
-                     syntax::ext::expand::expand_crate(sess.parse_sess,
-                                                       cfg.clone(),
-                                                       crate));
+    crate = time(time_passes, ~"expansion", ||
+                 syntax::ext::expand::expand_crate(sess.parse_sess, cfg.clone(),
+                                                   crate));
 
-        // strip again, in case expansion added anything with a #[cfg].
-        crate = time(time_passes, ~"configuration 2", ||
-                     front::config::strip_unconfigured_items(crate));
+    // strip again, in case expansion added anything with a #[cfg].
+    crate = time(time_passes, ~"configuration 2", ||
+                 front::config::strip_unconfigured_items(crate));
 
+    crate = time(time_passes, ~"maybe building test harness", ||
+                 front::test::modify_for_testing(sess, crate));
 
-        crate = time(time_passes, ~"maybe building test harness", ||
-                     front::test::modify_for_testing(sess, crate));
-    }
+    crate = time(time_passes, ~"std injection", ||
+                 front::std_inject::maybe_inject_libstd_ref(sess, crate));
 
-    if phases.to == cu_expand {
-        return (Some(crate), None);
-    }
+    return crate;
+}
 
-    assert!(phases.from != cu_no_trans);
+pub struct CrateAnalysis {
+    exp_map2: middle::resolve::ExportMap2,
+    ty_cx: ty::ctxt,
+    maps: astencode::Maps,
+    reachable: @mut HashSet<ast::node_id>
+}
 
-    let (llcx, llmod, link_meta) = {
-        crate = time(time_passes, ~"std injection", ||
-                     front::std_inject::maybe_inject_libstd_ref(sess, crate));
+/// Run the resolution, typechecking, region checking and other
+/// miscellaneous analysis passes on the crate. Return various
+/// structures carrying the results of the analysis.
+pub fn phase_3_run_analysis_passes(sess: Session,
+                                   crate: @ast::Crate) -> CrateAnalysis {
 
-        let ast_map = time(time_passes, ~"ast indexing", ||
-                           syntax::ast_map::map_crate(sess.diagnostic(), crate));
+    let time_passes = sess.time_passes();
+    let ast_map = time(time_passes, ~"ast indexing", ||
+                       syntax::ast_map::map_crate(sess.diagnostic(), crate));
 
-        time(time_passes, ~"external crate/lib resolution", ||
-             creader::read_crates(sess.diagnostic(), crate, sess.cstore,
-                                  sess.filesearch,
-                                  session::sess_os_to_meta_os(sess.targ_cfg.os),
-                                  sess.opts.is_static,
-                                  token::get_ident_interner()));
+    time(time_passes, ~"external crate/lib resolution", ||
+         creader::read_crates(sess.diagnostic(), crate, sess.cstore,
+                              sess.filesearch,
+                              session::sess_os_to_meta_os(sess.targ_cfg.os),
+                              sess.opts.is_static,
+                              token::get_ident_interner()));
 
-        let lang_items = time(time_passes, ~"language item collection", ||
-                              middle::lang_items::collect_language_items(crate, sess));
+    let lang_items = time(time_passes, ~"language item collection", ||
+                          middle::lang_items::collect_language_items(crate, sess));
 
-        let middle::resolve::CrateMap {
-            def_map: def_map,
-            exp_map2: exp_map2,
-            trait_map: trait_map
-        } =
-            time(time_passes, ~"resolution", ||
-                 middle::resolve::resolve_crate(sess, lang_items, crate));
+    let middle::resolve::CrateMap {
+        def_map: def_map,
+        exp_map2: exp_map2,
+        trait_map: trait_map
+    } =
+        time(time_passes, ~"resolution", ||
+             middle::resolve::resolve_crate(sess, lang_items, crate));
 
-        time(time_passes, ~"looking for entry point",
-             || middle::entry::find_entry_point(sess, crate, ast_map));
+    time(time_passes, ~"looking for entry point",
+         || middle::entry::find_entry_point(sess, crate, ast_map));
 
-        let freevars = time(time_passes, ~"freevar finding", ||
-                            freevars::annotate_freevars(def_map, crate));
+    let freevars = time(time_passes, ~"freevar finding", ||
+                        freevars::annotate_freevars(def_map, crate));
 
-        let region_map = time(time_passes, ~"region resolution", ||
-                              middle::region::resolve_crate(sess, def_map, crate));
+    let region_map = time(time_passes, ~"region resolution", ||
+                          middle::region::resolve_crate(sess, def_map, crate));
 
-        let rp_set = time(time_passes, ~"region parameterization inference", ||
-                          middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
+    let rp_set = time(time_passes, ~"region parameterization inference", ||
+                      middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
 
-        let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
-                                region_map, rp_set, lang_items);
+    let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
+                            region_map, rp_set, lang_items);
 
-        // passes are timed inside typeck
-        let (method_map, vtable_map) = typeck::check_crate(
-            ty_cx, trait_map, crate);
+    // passes are timed inside typeck
+    let (method_map, vtable_map) = typeck::check_crate(
+        ty_cx, trait_map, crate);
 
-        // These next two const passes can probably be merged
-        time(time_passes, ~"const marking", ||
-             middle::const_eval::process_crate(crate, ty_cx));
+    // These next two const passes can probably be merged
+    time(time_passes, ~"const marking", ||
+         middle::const_eval::process_crate(crate, ty_cx));
 
-        time(time_passes, ~"const checking", ||
-             middle::check_const::check_crate(sess, crate, ast_map, def_map,
-                                              method_map, ty_cx));
+    time(time_passes, ~"const checking", ||
+         middle::check_const::check_crate(sess, crate, ast_map, def_map,
+                                          method_map, ty_cx));
 
-        if phases.to == cu_typeck { return (Some(crate), Some(ty_cx)); }
+    time(time_passes, ~"privacy checking", ||
+         middle::privacy::check_crate(ty_cx, &method_map, crate));
 
-        time(time_passes, ~"privacy checking", ||
-             middle::privacy::check_crate(ty_cx, &method_map, crate));
+    time(time_passes, ~"effect checking", ||
+         middle::effect::check_crate(ty_cx, method_map, crate));
 
-        time(time_passes, ~"effect checking", ||
-             middle::effect::check_crate(ty_cx, method_map, crate));
+    time(time_passes, ~"loop checking", ||
+         middle::check_loop::check_crate(ty_cx, crate));
 
-        time(time_passes, ~"loop checking", ||
-             middle::check_loop::check_crate(ty_cx, crate));
+    let middle::moves::MoveMaps {moves_map, moved_variables_set,
+                                 capture_map} =
+        time(time_passes, ~"compute moves", ||
+             middle::moves::compute_moves(ty_cx, method_map, crate));
 
-        let middle::moves::MoveMaps {moves_map, moved_variables_set,
-                                     capture_map} =
-            time(time_passes, ~"compute moves", ||
-                 middle::moves::compute_moves(ty_cx, method_map, crate));
+    time(time_passes, ~"match checking", ||
+         middle::check_match::check_crate(ty_cx, method_map,
+                                          moves_map, crate));
 
-        time(time_passes, ~"match checking", ||
-             middle::check_match::check_crate(ty_cx, method_map,
-                                              moves_map, crate));
+    time(time_passes, ~"liveness checking", ||
+         middle::liveness::check_crate(ty_cx, method_map,
+                                       capture_map, crate));
 
-        time(time_passes, ~"liveness checking", ||
-             middle::liveness::check_crate(ty_cx, method_map,
+    let (root_map, write_guard_map) =
+        time(time_passes, ~"borrow checking", ||
+             middle::borrowck::check_crate(ty_cx, method_map,
+                                           moves_map, moved_variables_set,
                                            capture_map, crate));
 
-        let (root_map, write_guard_map) =
-            time(time_passes, ~"borrow checking", ||
-                 middle::borrowck::check_crate(ty_cx, method_map,
-                                               moves_map, moved_variables_set,
-                                               capture_map, crate));
+    time(time_passes, ~"kind checking", ||
+         kind::check_crate(ty_cx, method_map, crate));
 
-        time(time_passes, ~"kind checking", ||
-             kind::check_crate(ty_cx, method_map, crate));
+    let reachable_map =
+        time(time_passes, ~"reachability checking", ||
+             reachable::find_reachable(ty_cx, method_map, crate));
 
-        let reachable_map =
-            time(time_passes, ~"reachability checking", ||
-                reachable::find_reachable(ty_cx, method_map, crate));
+    time(time_passes, ~"lint checking", ||
+         lint::check_crate(ty_cx, crate));
 
-        time(time_passes, ~"lint checking", ||
-             lint::check_crate(ty_cx, crate));
-
-        if phases.to == cu_no_trans {
-            return (Some(crate), Some(ty_cx));
-        }
-
-        let maps = astencode::Maps {
+    CrateAnalysis {
+        exp_map2: exp_map2,
+        ty_cx: ty_cx,
+        maps: astencode::Maps {
             root_map: root_map,
             method_map: method_map,
             vtable_map: vtable_map,
             write_guard_map: write_guard_map,
             capture_map: capture_map
-        };
+        },
+        reachable: reachable_map
+    }
+}
 
-        let outputs = outputs.get_ref();
-        time(time_passes, ~"translation", ||
-             trans::base::trans_crate(sess,
-                                      crate,
-                                      ty_cx,
-                                      &outputs.obj_filename,
-                                      exp_map2,
-                                      reachable_map,
-                                      maps))
-    };
+pub struct CrateTranslation {
+    context: ContextRef,
+    module: ModuleRef,
+    link: LinkMeta
+}
 
-    let outputs = outputs.get_ref();
-    if (sess.opts.debugging_opts & session::print_link_args) != 0 {
-        io::println(link::link_args(sess, &outputs.obj_filename,
-                                    &outputs.out_filename, link_meta).connect(" "));
-    }
+/// Run the translation phase to LLVM, after which the AST and analysis can
+/// be discarded.
+pub fn phase_4_translate_to_llvm(sess: Session,
+                                 crate: @ast::Crate,
+                                 analysis: &CrateAnalysis,
+                                 outputs: &OutputFilenames) -> CrateTranslation {
+    time(sess.time_passes(), ~"translation", ||
+         trans::base::trans_crate(sess, crate, analysis,
+                                  &outputs.obj_filename))
+}
+
+/// Run LLVM itself, producing a bitcode file, assembly file or object file
+/// as a side effect.
+pub fn phase_5_run_llvm_passes(sess: Session,
+                               trans: &CrateTranslation,
+                               outputs: &OutputFilenames) {
 
     // NB: Android hack
     if sess.targ_cfg.arch == abi::Arm &&
-            (sess.opts.output_type == link::output_type_object ||
-             sess.opts.output_type == link::output_type_exe) {
+        (sess.opts.output_type == link::output_type_object ||
+         sess.opts.output_type == link::output_type_exe) {
         let output_type = link::output_type_assembly;
         let obj_filename = outputs.obj_filename.with_filetype("s");
 
-        time(time_passes, ~"LLVM passes", ||
-            link::write::run_passes(sess, llcx, llmod, output_type,
+        time(sess.time_passes(), ~"LLVM passes", ||
+            link::write::run_passes(sess,
+                                    trans.context,
+                                    trans.module,
+                                    output_type,
                                     &obj_filename));
 
         link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
     } else {
-        time(time_passes, ~"LLVM passes", ||
-            link::write::run_passes(sess, llcx, llmod, sess.opts.output_type,
+        time(sess.time_passes(), ~"LLVM passes", ||
+            link::write::run_passes(sess,
+                                    trans.context,
+                                    trans.module,
+                                    sess.opts.output_type,
                                     &outputs.obj_filename));
     }
+}
 
-    let stop_after_codegen =
-        sess.opts.output_type != link::output_type_exe ||
-        (sess.opts.is_static && *sess.building_library)   ||
-        sess.opts.jit;
-
-    if stop_after_codegen { return (None, None); }
-
-    time(time_passes, ~"linking", ||
+/// Run the linker on any artifacts that resulted from the LLVM run.
+/// This should produce either a finished executable or library.
+pub fn phase_6_link_output(sess: Session,
+                           trans: &CrateTranslation,
+                           outputs: &OutputFilenames) {
+    time(sess.time_passes(), ~"linking", ||
          link::link_binary(sess,
                            &outputs.obj_filename,
-                           &outputs.out_filename, link_meta));
+                           &outputs.out_filename,
+                           trans.link));
+}
 
-    return (None, None);
+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 compile_upto(sess: Session,
-                    cfg: ast::CrateConfig,
-                    input: &input,
-                    upto: compile_phase,
-                    outputs: Option<@OutputFilenames>)
-                    -> (Option<@ast::Crate>, Option<ty::ctxt>) {
-    let time_passes = sess.time_passes();
-    let crate = time(time_passes,
-                     ~"parsing",
-                     || parse_input(sess, cfg.clone(), input) );
-    if upto == cu_parse {
-        return (Some(crate), None);
+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;
     }
+    return false;
+}
 
-    compile_rest(sess,
-                 cfg,
-                 compile_upto {
-                    from: cu_parse,
-                    to: upto
-                 },
-                 outputs,
-                 Some(crate))
+pub fn stop_after_phase_5(sess: Session) -> bool {
+    if sess.opts.output_type != link::output_type_exe {
+        debug!("not building executable, returning early from compile_input");
+        return true;
+    }
+
+    if sess.opts.is_static && *sess.building_library {
+        debug!("building static library, returning early from compile_input");
+        return true;
+    }
+
+    if sess.opts.jit {
+        debug!("running JIT, returning early from compile_input");
+        return true;
+    }
+    return false;
 }
 
+#[fixed_stack_segment]
 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
                      outdir: &Option<Path>, output: &Option<Path>) {
-    let upto = if sess.opts.parse_only { cu_parse }
-               else if sess.opts.no_trans { cu_no_trans }
-               else { cu_everything };
-    let outputs = build_output_filenames(input, outdir, output, [], sess); // ???
-    compile_upto(sess, cfg, input, upto, Some(outputs));
+    let outputs = build_output_filenames(input, outdir, output, [], sess);
+    let crate = phase_1_parse_input(sess, cfg.clone(), input);
+    if stop_after_phase_1(sess) { return; }
+    let expanded_crate = phase_2_configure_and_expand(sess, cfg, crate);
+    let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
+    if stop_after_phase_3(sess) { return; }
+    let trans = phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
+    phase_5_run_llvm_passes(sess, &trans, outputs);
+    if stop_after_phase_5(sess) { return; }
+    phase_6_link_output(sess, &trans, outputs);
 }
 
 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
                           ppm: pp_mode) {
+
     fn ann_paren_for_expr(node: pprust::ann_node) {
         match node {
           pprust::node_expr(s, _) => pprust::popen(s),
@@ -447,37 +464,39 @@ pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
         }
     }
 
-    // Because the pretty printer needs to make a pass over the source
-    // to collect comments and literals, and we need to support reading
-    // from stdin, we're going to just suck the source into a string
-    // so both the parser and pretty-printer can use it.
-    let upto = match ppm {
-      ppm_expanded | ppm_expanded_identified => cu_expand,
-      ppm_typed => cu_typeck,
-      _ => cu_parse
+    let crate = phase_1_parse_input(sess, cfg.clone(), input);
+
+    let (crate, is_expanded) = match ppm {
+        ppm_expanded | ppm_expanded_identified | ppm_typed => {
+            (phase_2_configure_and_expand(sess, cfg, crate), true)
+        }
+        _ => (crate, false)
     };
-    let (crate, tcx) = compile_upto(sess, cfg, input, upto, None);
 
-    let ann = match ppm {
-      ppm_typed => {
-          pprust::pp_ann {pre: ann_paren_for_expr,
-                          post: |a| ann_typed_post(tcx.get(), a) }
-      }
-      ppm_identified | ppm_expanded_identified => {
-          pprust::pp_ann {pre: ann_paren_for_expr,
-                          post: ann_identified_post}
-      }
-      ppm_expanded | ppm_normal => {
-          pprust::no_ann()
-      }
+    let annotation = match ppm {
+        ppm_identified | ppm_expanded_identified => {
+            pprust::pp_ann {
+                pre: ann_paren_for_expr,
+                post: ann_identified_post
+            }
+        }
+        ppm_typed => {
+            let analysis = phase_3_run_analysis_passes(sess, crate);
+            pprust::pp_ann {
+                pre: ann_paren_for_expr,
+                post: |a| ann_typed_post(analysis.ty_cx, a)
+            }
+        }
+        _ => pprust::no_ann()
     };
-    let is_expanded = upto != cu_parse;
+
     let src = sess.codemap.get_filemap(source_name(input)).src;
     do io::with_str_reader(src) |rdr| {
         pprust::print_crate(sess.codemap, token::get_ident_interner(),
-                            sess.span_diagnostic, crate.unwrap(),
+                            sess.span_diagnostic, crate,
                             source_name(input),
-                            rdr, io::stdout(), ann, is_expanded);
+                            rdr, io::stdout(),
+                            annotation, is_expanded);
     }
 }
 
@@ -864,7 +883,7 @@ pub fn build_output_filenames(input: &input,
                               ofile: &Option<Path>,
                               attrs: &[ast::Attribute],
                               sess: Session)
-                           -> @OutputFilenames {
+                           -> ~OutputFilenames {
     let obj_path;
     let out_path;
     let sopts = sess.opts;
@@ -943,7 +962,7 @@ pub fn build_output_filenames(input: &input,
       }
     }
 
-    @OutputFilenames {
+    ~OutputFilenames {
         out_filename: out_path,
         obj_filename: obj_path
     }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 50ea6537544..5acd04437f9 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -28,7 +28,8 @@ use back::link::{mangle_exported_name};
 use back::{link, abi};
 use driver::session;
 use driver::session::Session;
-use lib::llvm::{ContextRef, ModuleRef, ValueRef, BasicBlockRef};
+use driver::driver::{CrateAnalysis, CrateTranslation};
+use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
 use lib::llvm::{llvm, True};
 use lib;
 use metadata::common::LinkMeta;
@@ -36,7 +37,6 @@ use metadata::{csearch, cstore, encoder};
 use middle::astencode;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::lang_items::{MallocFnLangItem, ClosureExchangeMallocFnLangItem};
-use middle::resolve;
 use middle::trans::_match;
 use middle::trans::adt;
 use middle::trans::base;
@@ -66,7 +66,7 @@ use util::ppaux::{Repr, ty_to_str};
 use middle::trans::type_::Type;
 
 use std::hash;
-use std::hashmap::{HashMap, HashSet};
+use std::hashmap::HashMap;
 use std::io;
 use std::libc::c_uint;
 use std::uint;
@@ -2957,12 +2957,8 @@ pub fn write_abi_version(ccx: &mut CrateContext) {
 
 pub fn trans_crate(sess: session::Session,
                    crate: &ast::Crate,
-                   tcx: ty::ctxt,
-                   output: &Path,
-                   emap2: resolve::ExportMap2,
-                   reachable_map: @mut HashSet<ast::node_id>,
-                   maps: astencode::Maps)
-                   -> (ContextRef, ModuleRef, LinkMeta) {
+                   analysis: &CrateAnalysis,
+                   output: &Path) -> CrateTranslation {
     // Before we touch LLVM, make sure that multithreading is enabled.
     if unsafe { !llvm::LLVMRustStartMultithreading() } {
         //sess.bug("couldn't enable multi-threaded LLVM");
@@ -2983,12 +2979,12 @@ pub fn trans_crate(sess: session::Session,
 
     let ccx = @mut CrateContext::new(sess,
                                      llmod_id,
-                                     tcx,
-                                     emap2,
-                                     maps,
+                                     analysis.ty_cx,
+                                     analysis.exp_map2,
+                                     analysis.maps,
                                      symbol_hasher,
                                      link_meta,
-                                     reachable_map);
+                                     analysis.reachable);
 
     {
         let _icx = push_ctxt("data");
@@ -3043,5 +3039,9 @@ pub fn trans_crate(sess: session::Session,
     let link_meta = ccx.link_meta;
     let llmod = ccx.llmod;
 
-    return (llcx, llmod, link_meta);
+    return CrateTranslation {
+        context: llcx,
+        module: llmod,
+        link: link_meta
+    };
 }
diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs
index 38c70f8be05..0c1f4e203aa 100644
--- a/src/librusti/rusti.rs
+++ b/src/librusti/rusti.rs
@@ -223,13 +223,15 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
     debug!("testing with ^^^^^^ %?", (||{ println(test) })());
     let dinput = driver::str_input(test.to_managed());
     let cfg = driver::build_configuration(sess, binary, &dinput);
-    let outputs = driver::build_output_filenames(&dinput, &None, &None, [], sess);
-    let (crate, tcx) = driver::compile_upto(sess, cfg.clone(), &dinput,
-                                            driver::cu_typeck, Some(outputs));
+
+    let crate = driver::phase_1_parse_input(sess, cfg.clone(), &dinput);
+    let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
+    let analysis = driver::phase_3_run_analysis_passes(sess, expanded_crate);
+
     // Once we're typechecked, record the types of all local variables defined
     // in this input
-    do find_main(crate.expect("crate after cu_typeck"), sess) |blk| {
-        program.register_new_vars(blk, tcx.expect("tcx after cu_typeck"));
+    do find_main(crate, sess) |blk| {
+        program.register_new_vars(blk, analysis.ty_cx);
     }
 
     //
@@ -242,8 +244,12 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
     let cfg = driver::build_configuration(sess, binary, &input);
     let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
     let sess = driver::build_session(options, diagnostic::emit);
-    driver::compile_upto(sess, cfg, &input, driver::cu_everything,
-                         Some(outputs));
+
+    let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
+    let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
+    let analysis = driver::phase_3_run_analysis_passes(sess, expanded_crate);
+    let trans = driver::phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
+    driver::phase_5_run_llvm_passes(sess, &trans, outputs);
 
     //
     // Stage 4: Inform the program that computation is done so it can update all
@@ -265,10 +271,7 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
         let code = fmt!("fn main() {\n %s \n}", input);
         let input = driver::str_input(code.to_managed());
         let cfg = driver::build_configuration(sess, binary, &input);
-        let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
-        let (crate, _) = driver::compile_upto(sess, cfg, &input,
-                                              driver::cu_parse, Some(outputs));
-        crate.expect("parsing should return a crate")
+        driver::phase_1_parse_input(sess, cfg.clone(), &input)
     }
 
     fn find_main(crate: @ast::Crate, sess: session::Session,
@@ -334,9 +337,12 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
             None => { },
         }
         if (should_compile) {
-            printfln!("compiling %s...", src_filename);
-            driver::compile_upto(sess, cfg, &input, driver::cu_everything,
-                                 Some(outputs));
+            println(fmt!("compiling %s...", src_filename));
+            let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
+            let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
+            let analysis = driver::phase_3_run_analysis_passes(sess, expanded_crate);
+            let trans = driver::phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
+            driver::phase_5_run_llvm_passes(sess, &trans, outputs);
             true
         } else { false }
     } {
diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs
index 770c073fa2a..b2aa53f3ab1 100644
--- a/src/librustpkg/rustpkg.rs
+++ b/src/librustpkg/rustpkg.rs
@@ -109,7 +109,8 @@ impl<'self> PkgScript<'self> {
         let input = driver::file_input(script);
         let sess = driver::build_session(options, diagnostic::emit);
         let cfg = driver::build_configuration(sess, binary, &input);
-        let (crate, _) = driver::compile_upto(sess, cfg.clone(), &input, driver::cu_parse, None);
+        let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
+        let crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
         let work_dir = build_pkg_id_in_workspace(id, workspace);
 
         debug!("Returning package script with id %?", id);
@@ -119,7 +120,7 @@ impl<'self> PkgScript<'self> {
             input: input,
             sess: sess,
             cfg: cfg,
-            crate: crate.unwrap(),
+            crate: crate,
             build_dir: work_dir
         }
     }
@@ -142,14 +143,10 @@ impl<'self> PkgScript<'self> {
                 let root = r.pop().pop().pop().pop(); // :-\
                 debug!("Root is %s, calling compile_rest", root.to_str());
                 let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
-                let binary = os::args()[0].to_managed();
                 util::compile_crate_from_input(&self.input,
                                                &self.build_dir,
                                                sess,
-                                               crate,
-                                               driver::build_configuration(sess,
-                                                                           binary, &self.input),
-                                               driver::cu_parse);
+                                               crate);
                 debug!("Running program: %s %s %s %s", exe.to_str(),
                        sysroot.to_str(), root.to_str(), "install");
                 // FIXME #7401 should support commands besides `install`
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 60367fd9aa6..12d3f4fcfce 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -18,7 +18,6 @@ use syntax::ext::base::ExtCtxt;
 use syntax::{ast, attr, codemap, diagnostic, fold};
 use syntax::attr::AttrMetaMethods;
 use rustc::back::link::output_type_exe;
-use rustc::driver::driver::compile_upto;
 use rustc::driver::session::{lib_crate, bin_crate};
 use context::Ctx;
 use package_id::PkgId;
@@ -220,12 +219,8 @@ pub fn compile_input(ctxt: &Ctx,
     // Infer dependencies that rustpkg needs to build, by scanning for
     // `extern mod` directives.
     let cfg = driver::build_configuration(sess, binary, &input);
-    let (crate_opt, _) = driver::compile_upto(sess, cfg.clone(), &input, driver::cu_expand, None);
-
-    let mut crate = match crate_opt {
-        Some(c) => c,
-        None => fail!("compile_input expected...")
-    };
+    let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
+    crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
 
     // Not really right. Should search other workspaces too, and the installed
     // database (which doesn't exist yet)
@@ -257,7 +252,7 @@ pub fn compile_input(ctxt: &Ctx,
 
     debug!("calling compile_crate_from_input, out_dir = %s,
            building_library = %?", out_dir.to_str(), sess.building_library);
-    compile_crate_from_input(&input, out_dir, sess, crate, cfg.clone(), driver::cu_expand);
+    compile_crate_from_input(&input, out_dir, sess, crate);
     true
 }
 
@@ -269,9 +264,7 @@ pub fn compile_input(ctxt: &Ctx,
 pub fn compile_crate_from_input(input: &driver::input,
                                 build_dir: &Path,
                                 sess: session::Session,
-                                crate: @ast::Crate,
-                                cfg: ast::CrateConfig,
-                                compile_from: driver::compile_phase) {
+                                crate: @ast::Crate) {
     debug!("Calling build_output_filenames with %s, building library? %?",
            build_dir.to_str(), sess.building_library);
 
@@ -284,15 +277,13 @@ pub fn compile_crate_from_input(input: &driver::input,
     for sess.opts.addl_lib_search_paths.iter().advance |lib| {
         debug!("an additional library: %s", lib.to_str());
     }
-
-    driver::compile_rest(sess,
-                         cfg,
-                         compile_upto {
-                             from: compile_from,
-                             to: driver::cu_everything
-                         },
-                         Some(outputs),
-                         Some(crate));
+    let analysis = driver::phase_3_run_analysis_passes(sess, crate);
+    let translation = driver::phase_4_translate_to_llvm(sess, crate,
+                                                        &analysis,
+                                                        outputs);
+    driver::phase_5_run_llvm_passes(sess, &translation, outputs);
+    if driver::stop_after_phase_5(sess) { return; }
+    driver::phase_6_link_output(sess, &translation, outputs);
 }
 
 #[cfg(windows)]