driver.rs 35.6 KB
Newer Older
S
Steven Fackler 已提交
1
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use rustc::session::Session;
12
use rustc::session::config::{self, Input, OutputFilenames};
13
use rustc::session::search_paths::PathKind;
14
use rustc::lint;
K
Keegan McAllister 已提交
15
use rustc::metadata::creader::CrateReader;
16
use rustc::middle::{stability, ty, reachable};
17 18 19 20 21 22
use rustc::middle::dependency_format;
use rustc::middle;
use rustc::plugin::load::Plugins;
use rustc::plugin::registry::Registry;
use rustc::plugin;
use rustc::util::common::time;
23
use rustc_borrowck as borrowck;
24
use rustc_resolve as resolve;
25 26 27
use rustc_trans::back::link;
use rustc_trans::back::write;
use rustc_trans::trans;
N
Niko Matsakis 已提交
28
use rustc_typeck as typeck;
29
use rustc_privacy;
30

31
use serialize::json;
32

A
Alex Crichton 已提交
33 34
use std::old_io;
use std::old_io::fs;
35
use std::os;
36
use syntax::ast;
37
use syntax::ast_map;
38
use syntax::attr;
39
use syntax::attr::{AttrMetaMethods};
40
use syntax::diagnostics;
41
use syntax::parse;
J
John Clements 已提交
42
use syntax::parse::token;
43
use syntax;
H
Haitao Li 已提交
44

N
Nick Cameron 已提交
45 46 47 48
pub fn compile_input(sess: Session,
                     cfg: ast::CrateConfig,
                     input: &Input,
                     outdir: &Option<Path>,
49
                     output: &Option<Path>,
50 51 52 53 54 55 56 57 58 59 60 61
                     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;
        }
    })}

N
Nick Cameron 已提交
62 63 64 65
    // 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) = {
66
        let (outputs, expanded_crate, id) = {
N
Nick Cameron 已提交
67
            let krate = phase_1_parse_input(&sess, cfg, input);
68 69 70 71 72 73 74

            controller_entry_point!(after_parse,
                                    CompileState::state_after_parse(input,
                                                                    &sess,
                                                                    outdir,
                                                                    &krate));

N
Nick Cameron 已提交
75 76 77
            let outputs = build_output_filenames(input,
                                                 outdir,
                                                 output,
J
Jorge Aparicio 已提交
78
                                                 &krate.attrs[],
N
Nick Cameron 已提交
79
                                                 &sess);
80 81
            let id = link::find_crate_name(Some(&sess),
                                           &krate.attrs[],
82
                                           input);
83
            let expanded_crate
84 85 86
                = match phase_2_configure_and_expand(&sess,
                                                     krate,
                                                     &id[],
87
                                                     addl_plugins) {
88
                    None => return,
89
                    Some(k) => k
90 91
                };

92
            (outputs, expanded_crate, id)
N
Nick Cameron 已提交
93
        };
94

95 96 97 98 99 100 101
        controller_entry_point!(after_expand,
                                CompileState::state_after_expand(input,
                                                                 &sess,
                                                                 outdir,
                                                                 &expanded_crate,
                                                                 &id[]));

102 103 104
        let mut forest = ast_map::Forest::new(expanded_crate);
        let ast_map = assign_node_ids_and_map(&sess, &mut forest);

J
Jorge Aparicio 已提交
105
        write_out_deps(&sess, input, &outputs, &id[]);
N
Nick Cameron 已提交
106

107 108 109 110 111 112 113
        controller_entry_point!(after_write_deps,
                                CompileState::state_after_write_deps(input,
                                                                     &sess,
                                                                     outdir,
                                                                     &ast_map,
                                                                     &id[]));

114
        let arenas = ty::CtxtArenas::new();
115 116 117 118 119 120 121 122 123 124 125 126 127
        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));
128 129

        if log_enabled!(::log::INFO) {
H
Huon Wilson 已提交
130
            println!("Pre-trans");
131 132
            analysis.ty_cx.print_debug_stats();
        }
133
        let (tcx, trans) = phase_4_translate_to_llvm(analysis);
N
Nick Cameron 已提交
134

135
        if log_enabled!(::log::INFO) {
H
Huon Wilson 已提交
136
            println!("Post-trans");
137 138 139
            tcx.print_debug_stats();
        }

N
Nick Cameron 已提交
140 141 142 143 144 145
        // Discard interned strings as they are no longer required.
        token::get_ident_interner().clear();

        (outputs, trans, tcx.sess)
    };
    phase_5_run_llvm_passes(&sess, &trans, &outputs);
146 147 148 149 150 151 152

    controller_entry_point!(after_llvm,
                            CompileState::state_after_llvm(input,
                                                           &sess,
                                                           outdir,
                                                           &trans));

N
Nick Cameron 已提交
153
    phase_6_link_output(&sess, &trans, &outputs);
154
}
H
Haitao Li 已提交
155

S
Steve Klabnik 已提交
156 157
/// The name used for source code that doesn't originate in a file
/// (e.g. source from stdin or a string)
158
pub fn anon_src() -> String {
159
    "<anon>".to_string()
P
Patrick Walton 已提交
160
}
161

162
pub fn source_name(input: &Input) -> String {
163
    match *input {
E
Eduard Burtescu 已提交
164
        // FIXME (#9639): This needs to handle non-utf8 paths
165 166
        Input::File(ref ifile) => ifile.as_str().unwrap().to_string(),
        Input::Str(_) => anon_src()
167 168 169
    }
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
/// 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>,
187
    pub after_write_deps: PhaseController<'a>,
188 189 190 191 192 193 194 195 196 197 198
    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(),
199
            after_write_deps:  PhaseController::basic(),
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
            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)
        }
    }

284 285 286 287 288 289 290 291 292 293 294 295 296
    fn state_after_write_deps(input: &'a Input,
                              session: &'a Session,
                              out_dir: &'a Option<Path>,
                              ast_map: &'a ast_map::Map<'ast>,
                              crate_name: &'a str)
                              -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            crate_name: Some(crate_name),
            ast_map: Some(ast_map),
            .. CompileState::empty(input, session, out_dir)
        }
    }

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    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)
        }
    }
}

E
Eduard Burtescu 已提交
325
pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
A
Alex Crichton 已提交
326
    -> ast::Crate {
M
Murarth 已提交
327 328 329 330 331 332
    // These may be left in an incoherent state after a previous compile.
    // `clear_tables` and `get_ident_interner().clear()` can be used to free
    // memory, but they do not restore the initial state.
    syntax::ext::mtwt::reset_tables();
    token::reset_ident_interner();

333
    let krate = time(sess.time_passes(), "parsing", (), |_| {
334
        match *input {
335
            Input::File(ref file) => {
E
Eduard Burtescu 已提交
336
                parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
337
            }
338
            Input::Str(ref src) => {
339 340
                parse::parse_crate_from_source_str(anon_src().to_string(),
                                                   src.to_string(),
341
                                                   cfg.clone(),
E
Eduard Burtescu 已提交
342
                                                   &sess.parse_sess)
343 344
            }
        }
345 346
    });

347
    if sess.opts.debugging_opts.ast_json_noexpand {
348
        println!("{}", json::as_json(&krate));
349 350
    }

S
Seo Sanghyeon 已提交
351 352
    if let Some(ref s) = sess.opts.show_span {
        syntax::show_span::run(sess.diagnostic(), s.as_slice(), &krate);
353 354
    }

355
    krate
356
}
H
Haitao Li 已提交
357

358 359
// For continuing compilation after a parsed crate has been
// modified
360

361
/// Run the "early phases" of the compiler: initial `cfg` processing,
B
Brian Anderson 已提交
362
/// loading compiler plugins (including those from `addl_plugins`),
363 364 365
/// 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.
366 367
///
/// Returns `None` if we're aborting after handling -W help.
E
Eduard Burtescu 已提交
368
pub fn phase_2_configure_and_expand(sess: &Session,
369
                                    mut krate: ast::Crate,
370
                                    crate_name: &str,
371
                                    addl_plugins: Option<Vec<String>>)
372
                                    -> Option<ast::Crate> {
373
    let time_passes = sess.time_passes();
H
Haitao Li 已提交
374

375
    *sess.crate_types.borrow_mut() =
J
Jorge Aparicio 已提交
376
        collect_crate_types(sess, &krate.attrs[]);
377
    *sess.crate_metadata.borrow_mut() =
J
Jorge Aparicio 已提交
378
        collect_crate_metadata(sess, &krate.attrs[]);
379

380 381 382 383
    time(time_passes, "recursion limit", (), |_| {
        middle::recursion_limit::update_recursion_limit(sess, &krate);
    });

384 385 386
    // strip before expansion to allow macros to depend on
    // configuration variables e.g/ in
    //
387
    //   #[macro_use] #[cfg(foo)]
388 389 390
    //   mod bar { macro_rules! baz!(() => {{}}) }
    //
    // baz! should not use this definition unless foo is enabled.
391

C
Corey Richardson 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    time(time_passes, "gated macro checking", (), |_| {
        let (features, unknown_features) =
            syntax::feature_gate::check_crate_macros(sess.codemap(),
                                                     &sess.parse_sess.span_diagnostic,
                                                     &krate);
        for uf in unknown_features.iter() {
            sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
                          ast::CRATE_NODE_ID,
                          *uf,
                          "unknown feature".to_string());
        }

        // these need to be set "early" so that expansion sees `quote` if enabled.
        *sess.features.borrow_mut() = features;
        sess.abort_if_errors();
    });

409
    krate = time(time_passes, "configuration 1", krate, |krate|
410
                 syntax::config::strip_unconfigured_items(sess.diagnostic(), krate));
411

412 413
    krate = time(time_passes, "crate injection", krate, |krate|
                 syntax::std_inject::maybe_inject_crates_ref(krate,
A
Aaron Turon 已提交
414
                                                             sess.opts.alt_std_name.clone()));
415

416
    let mut addl_plugins = Some(addl_plugins);
417 418
    let Plugins { macros, registrars }
        = time(time_passes, "plugin loading", (), |_|
419
               plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
420

421
    let mut registry = Registry::new(sess, &krate);
422

423
    time(time_passes, "plugin registration", registrars, |registrars| {
N
Nick Cameron 已提交
424
        if sess.features.borrow().rustc_diagnostic_macros {
425 426 427 428 429 430 431 432
            registry.register_macro("__diagnostic_used",
                diagnostics::plugin::expand_diagnostic_used);
            registry.register_macro("__register_diagnostic",
                diagnostics::plugin::expand_register_diagnostic);
            registry.register_macro("__build_diagnostic_array",
                diagnostics::plugin::expand_build_diagnostic_array);
        }

433 434 435
        for registrar in registrars.into_iter() {
            registry.args_hidden = Some(registrar.args);
            (registrar.fun)(&mut registry);
436
        }
437
    });
438

439
    let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry;
440

K
Keegan McAllister 已提交
441 442
    {
        let mut ls = sess.lint_store.borrow_mut();
A
Aaron Turon 已提交
443
        for pass in lint_passes.into_iter() {
K
Keegan McAllister 已提交
444 445
            ls.register_pass(Some(sess), true, pass);
        }
446

A
Aaron Turon 已提交
447
        for (name, to) in lint_groups.into_iter() {
448 449
            ls.register_group(Some(sess), true, name, to);
        }
K
Keegan McAllister 已提交
450 451 452
    }

    // Lint plugins are registered; now we can process command line flags.
453
    if sess.opts.describe_lints {
K
Keegan McAllister 已提交
454
        super::describe_lints(&*sess.lint_store.borrow(), true);
455 456 457 458 459 460 461
        return None;
    }
    sess.lint_store.borrow_mut().process_command_line(sess);

    // Abort if there are errors from lint processing or a plugin registrar.
    sess.abort_if_errors();

462 463 464 465 466 467 468
    krate = time(time_passes, "expansion", (krate, macros, syntax_exts),
        |(krate, macros, syntax_exts)| {
            // Windows dlls do not have rpaths, so they don't know how to find their
            // dependencies. It's up to us to tell the system where to find all the
            // dependent dlls. Note that this uses cfg!(windows) as opposed to
            // targ_cfg because syntax extensions are always loaded for the host
            // compiler, not for the target.
469
            let mut _old_path = String::new();
470
            if cfg!(windows) {
471
                _old_path = os::getenv("PATH").unwrap_or(_old_path);
472
                let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
J
Jorge Aparicio 已提交
473 474
                new_path.extend(os::split_paths(&_old_path[]).into_iter());
                os::setenv("PATH", os::join_paths(&new_path[]).unwrap());
475 476
            }
            let cfg = syntax::ext::expand::ExpansionConfig {
477
                crate_name: crate_name.to_string(),
478
                enable_quotes: sess.features.borrow().quote,
479
                recursion_limit: sess.recursion_limit.get(),
480
            };
481
            let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
482 483 484
                                              cfg,
                                              macros,
                                              syntax_exts,
485 486 487 488 489
                                              krate);
            if cfg!(windows) {
                os::setenv("PATH", _old_path);
            }
            ret
490 491 492
        }
    );

C
Corey Richardson 已提交
493 494 495 496 497 498 499 500
    // Needs to go *after* expansion to be able to check the results of macro expansion.
    time(time_passes, "complete gated feature checking", (), |_| {
        syntax::feature_gate::check_crate(sess.codemap(),
                                          &sess.parse_sess.span_diagnostic,
                                          &krate);
        sess.abort_if_errors();
    });

J
John Clements 已提交
501 502
    // JBC: make CFG processing part of expansion to avoid this problem:

503
    // strip again, in case expansion added anything with a #[cfg].
504
    krate = time(time_passes, "configuration 2", krate, |krate|
505
                 syntax::config::strip_unconfigured_items(sess.diagnostic(), krate));
506

507
    krate = time(time_passes, "maybe building test harness", krate, |krate|
N
Nick Cameron 已提交
508 509 510 511
                 syntax::test::modify_for_testing(&sess.parse_sess,
                                                  &sess.opts.cfg,
                                                  krate,
                                                  sess.diagnostic()));
512

513
    krate = time(time_passes, "prelude injection", krate, |krate|
N
Nick Cameron 已提交
514
                 syntax::std_inject::maybe_inject_prelude(krate));
B
Brian Anderson 已提交
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
    time(time_passes, "checking that all macro invocations are gone", &krate, |krate|
         syntax::ext::expand::check_for_macros(&sess.parse_sess, krate));

    Some(krate)
}

pub fn assign_node_ids_and_map<'ast>(sess: &Session,
                                     forest: &'ast mut ast_map::Forest)
                                     -> ast_map::Map<'ast> {
    struct NodeIdAssigner<'a> {
        sess: &'a Session
    }

    impl<'a> ast_map::FoldOps for NodeIdAssigner<'a> {
        fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
            assert_eq!(old_id, ast::DUMMY_NODE_ID);
            self.sess.next_node_id()
        }
    }

    let map = time(sess.time_passes(), "assigning node ids and indexing ast", forest, |forest|
                   ast_map::map_crate(forest, NodeIdAssigner { sess: sess }));
538

539
    if sess.opts.debugging_opts.ast_json {
540
        println!("{}", json::as_json(map.krate()));
541 542
    }

543
    map
544
}
545

546 547 548
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
549
pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
550
                                         ast_map: ast_map::Map<'tcx>,
551
                                         arenas: &'tcx ty::CtxtArenas<'tcx>,
552 553 554
                                         name: String,
                                         make_glob_map: resolve::MakeGlobMap)
                                         -> ty::CrateAnalysis<'tcx> {
555
    let time_passes = sess.time_passes();
556
    let krate = ast_map.krate();
557

558
    time(time_passes, "external crate/lib resolution", (), |_|
K
Keegan McAllister 已提交
559
         CrateReader::new(&sess).read_crates(krate));
B
Brian Anderson 已提交
560

561
    let lang_items = time(time_passes, "language item collection", (), |_|
E
Eduard Burtescu 已提交
562
                          middle::lang_items::collect_language_items(krate, &sess));
563

N
Nick Cameron 已提交
564
    let resolve::CrateMap {
565 566 567
        def_map,
        freevars,
        capture_mode_map,
568
        export_map,
569 570
        trait_map,
        external_exports,
571 572
        last_private_map,
        glob_map,
573
    } =
574
        time(time_passes, "resolution", (),
575
             |_| resolve::resolve_crate(&sess,
N
Nick Cameron 已提交
576
                                        &ast_map,
577 578 579
                                        &lang_items,
                                        krate,
                                        make_glob_map));
B
Brian Anderson 已提交
580

581 582 583
    // Discard MTWT tables that aren't required past resolution.
    syntax::ext::mtwt::clear_tables();

584
    let named_region_map = time(time_passes, "lifetime resolution", (),
585
                                |_| middle::resolve_lifetime::krate(&sess, krate, &def_map));
586

587
    time(time_passes, "looking for entry point", (),
588
         |_| middle::entry::find_entry_point(&sess, &ast_map));
B
Brian Anderson 已提交
589

590 591 592
    sess.plugin_registrar_fn.set(
        time(time_passes, "looking for plugin registrar", (), |_|
            plugin::build::find_plugin_registrar(
593
                sess.diagnostic(), krate)));
594

595
    let region_map = time(time_passes, "region resolution", (), |_|
E
Eduard Burtescu 已提交
596
                          middle::region::resolve_crate(&sess, krate));
597

598 599 600
    time(time_passes, "loop checking", (), |_|
         middle::check_loop::check_crate(&sess, krate));

A
Aaron Turon 已提交
601 602 603
    let stability_index = time(time_passes, "stability index", (), |_|
                               stability::Index::build(krate));

604 605 606
    time(time_passes, "static item recursion checking", (), |_|
         middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));

607
    let ty_cx = ty::mk_ctxt(sess,
608
                            arenas,
609 610 611 612
                            def_map,
                            named_region_map,
                            ast_map,
                            freevars,
613
                            capture_mode_map,
614 615 616
                            region_map,
                            lang_items,
                            stability_index);
617

618
    // passes are timed inside typeck
619
    typeck::check_crate(&ty_cx, trait_map);
B
Brian Anderson 已提交
620

621
    time(time_passes, "check static items", (), |_|
622
         middle::check_static::check_crate(&ty_cx));
623

624
    // These next two const passes can probably be merged
625
    time(time_passes, "const marking", (), |_|
626
         middle::const_eval::process_crate(&ty_cx));
B
Brian Anderson 已提交
627

628
    time(time_passes, "const checking", (), |_|
629
         middle::check_const::check_crate(&ty_cx));
B
Brian Anderson 已提交
630

631
    let maps = (external_exports, last_private_map);
A
Alex Crichton 已提交
632 633
    let (exported_items, public_items) =
            time(time_passes, "privacy checking", maps, |(a, b)|
634
                 rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
B
Brian Anderson 已提交
635

636
    time(time_passes, "intrinsic checking", (), |_|
637
         middle::intrinsicck::check_crate(&ty_cx));
638

639
    time(time_passes, "effect checking", (), |_|
640
         middle::effect::check_crate(&ty_cx));
641

642
    time(time_passes, "match checking", (), |_|
643
         middle::check_match::check_crate(&ty_cx));
644

645
    time(time_passes, "liveness checking", (), |_|
646
         middle::liveness::check_crate(&ty_cx));
647

648
    time(time_passes, "borrow checking", (), |_|
649
         borrowck::check_crate(&ty_cx));
650

N
Nick Cameron 已提交
651 652 653
    time(time_passes, "rvalue checking", (), |_|
         middle::check_rvalues::check_crate(&ty_cx, krate));

654 655 656 657 658 659
    // Avoid overwhelming user with errors if type checking failed.
    // I'm not sure how helpful this is, to be honest, but it avoids a
    // lot of annoying errors in the compile-fail tests (basically,
    // lint warnings and so on -- kindck used to do this abort, but
    // kindck is gone now). -nmatsakis
    ty_cx.sess.abort_if_errors();
J
James Miller 已提交
660

661
    let reachable_map =
662
        time(time_passes, "reachability checking", (), |_|
663
             reachable::find_reachable(&ty_cx, &exported_items));
J
James Miller 已提交
664

E
Eduard Burtescu 已提交
665 666 667
    time(time_passes, "death checking", (), |_| {
        middle::dead::check_crate(&ty_cx,
                                  &exported_items,
668
                                  &reachable_map)
E
Eduard Burtescu 已提交
669
    });
K
Kiet Tran 已提交
670

671
    time(time_passes, "lint checking", (), |_|
672
         lint::check_crate(&ty_cx, &exported_items));
673

674
    ty::CrateAnalysis {
675
        export_map: export_map,
676
        ty_cx: ty_cx,
677
        exported_items: exported_items,
A
Alex Crichton 已提交
678
        public_items: public_items,
679
        reachable: reachable_map,
680
        name: name,
681
        glob_map: glob_map,
682 683
    }
}
J
James Miller 已提交
684

685 686
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
687 688
pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
                                       -> (ty::ctxt<'tcx>, trans::CrateTranslation) {
689
    let time_passes = analysis.ty_cx.sess.time_passes();
690 691 692 693 694

    time(time_passes, "resolving dependency formats", (), |_|
         dependency_format::calculate(&analysis.ty_cx));

    // Option dance to work around the lack of stack once closures.
695
    time(time_passes, "translation", analysis, |analysis|
696
         trans::trans_crate(analysis))
697 698 699 700
}

/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
E
Eduard Burtescu 已提交
701
pub fn phase_5_run_llvm_passes(sess: &Session,
702
                               trans: &trans::CrateTranslation,
703
                               outputs: &OutputFilenames) {
704
    if sess.opts.cg.no_integrated_as {
705
        let output_type = config::OutputTypeAssembly;
706

707
        time(sess.time_passes(), "LLVM passes", (), |_|
N
Nick Cameron 已提交
708
            write::run_passes(sess, trans, &[output_type], outputs));
709

710
        write::run_assembler(sess, outputs);
V
Vadim Chugunov 已提交
711

712
        // Remove assembly source, unless --save-temps was specified
713
        if !sess.opts.cg.save_temps {
714
            fs::unlink(&outputs.temp_path(config::OutputTypeAssembly)).unwrap();
V
Vadim Chugunov 已提交
715
        }
716
    } else {
717
        time(sess.time_passes(), "LLVM passes", (), |_|
718 719
            write::run_passes(sess,
                              trans,
J
Jorge Aparicio 已提交
720
                              &sess.opts.output_types[],
721
                              outputs));
722
    }
723 724

    sess.abort_if_errors();
725
}
H
Haitao Li 已提交
726

727 728
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
E
Eduard Burtescu 已提交
729
pub fn phase_6_link_output(sess: &Session,
730
                           trans: &trans::CrateTranslation,
731
                           outputs: &OutputFilenames) {
732
    let old_path = os::getenv("PATH").unwrap_or_else(||String::new());
733
    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
J
Jorge Aparicio 已提交
734 735
    new_path.extend(os::split_paths(&old_path[]).into_iter());
    os::setenv("PATH", os::join_paths(&new_path[]).unwrap());
736

737
    time(sess.time_passes(), "linking", (), |_|
738
         link::link_binary(sess,
739
                           trans,
A
Alex Crichton 已提交
740
                           outputs,
J
Jorge Aparicio 已提交
741
                           &trans.link.crate_name[]));
742 743

    os::setenv("PATH", old_path);
744 745
}

746 747 748 749 750 751
fn escape_dep_filename(filename: &str) -> String {
    // Apparently clang and gcc *only* escape spaces:
    // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
    filename.replace(" ", "\\ ")
}

E
Eduard Burtescu 已提交
752
fn write_out_deps(sess: &Session,
A
Alex Crichton 已提交
753 754
                  input: &Input,
                  outputs: &OutputFilenames,
755
                  id: &str) {
756

757
    let mut out_filenames = Vec::new();
A
Alex Crichton 已提交
758 759 760
    for output_type in sess.opts.output_types.iter() {
        let file = outputs.path(*output_type);
        match *output_type {
761
            config::OutputTypeExe => {
762
                for output in sess.crate_types.borrow().iter() {
763 764
                    let p = link::filename_for_input(sess, *output,
                                                     id, &file);
A
Alex Crichton 已提交
765 766 767 768 769 770
                    out_filenames.push(p);
                }
            }
            _ => { out_filenames.push(file); }
        }
    }
771

A
Alex Crichton 已提交
772 773
    // Write out dependency rules to the dep-info file if requested with
    // --dep-info
774 775 776
    let deps_filename = match sess.opts.write_dependency_info {
        // Use filename from --dep-file argument if given
        (true, Some(ref filename)) => filename.clone(),
A
Alex Crichton 已提交
777 778
        // Use default filename: crate source filename with extension replaced
        // by ".d"
779
        (true, None) => match *input {
780 781
            Input::File(..) => outputs.with_extension("d"),
            Input::Str(..) => {
A
Alex Crichton 已提交
782 783
                sess.warn("can not write --dep-info without a filename \
                           when compiling stdin.");
784
                return
785 786
            },
        },
787
        _ => return,
788
    };
789

A
Alex Crichton 已提交
790
    let result = (|&:| -> old_io::IoResult<()> {
791 792
        // Build a list of files used to compile the output and
        // write Makefile-compatible dependency rules
793
        let files: Vec<String> = sess.codemap().files.borrow()
794
                                   .iter().filter(|fmap| fmap.is_real_file())
J
Jorge Aparicio 已提交
795
                                   .map(|fmap| escape_dep_filename(&fmap.name[]))
796
                                   .collect();
A
Alex Crichton 已提交
797
        let mut file = try!(old_io::File::create(&deps_filename));
798 799 800 801 802 803 804 805 806 807
        for path in out_filenames.iter() {
            try!(write!(&mut file as &mut Writer,
                          "{}: {}\n\n", path.display(), files.connect(" ")));
        }
        Ok(())
    })();

    match result {
        Ok(()) => {}
        Err(e) => {
J
Jorge Aparicio 已提交
808 809
            sess.fatal(&format!("error writing dependencies to `{}`: {}",
                               deps_filename.display(), e)[]);
810
        }
811
    }
812 813
}

N
Nick Cameron 已提交
814 815
pub fn collect_crate_types(session: &Session,
                           attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
816 817 818 819
    // Unconditionally collect crate types from attributes to make them used
    let attr_types: Vec<config::CrateType> = attrs.iter().filter_map(|a| {
        if a.check_name("crate_type") {
            match a.value_str() {
820
                Some(ref n) if *n == "rlib" => {
821 822
                    Some(config::CrateTypeRlib)
                }
823
                Some(ref n) if *n == "dylib" => {
824 825
                    Some(config::CrateTypeDylib)
                }
826
                Some(ref n) if *n == "lib" => {
827 828
                    Some(config::default_lib_output())
                }
829
                Some(ref n) if *n == "staticlib" => {
830 831
                    Some(config::CrateTypeStaticlib)
                }
832
                Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
833
                Some(_) => {
A
Aaron Turon 已提交
834
                    session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
835 836 837
                                     ast::CRATE_NODE_ID,
                                     a.span,
                                     "invalid `crate_type` \
838
                                      value".to_string());
839 840 841
                    None
                }
                _ => {
A
Aaron Turon 已提交
842
                    session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
843 844 845
                                     ast::CRATE_NODE_ID,
                                     a.span,
                                     "`crate_type` requires a \
846
                                      value".to_string());
847 848 849 850 851 852 853 854
                    None
                }
            }
        } else {
            None
        }
    }).collect();

N
Nick Cameron 已提交
855 856 857 858
    // If we're generating a test executable, then ignore all other output
    // styles at all other locations
    if session.opts.test {
        return vec!(config::CrateTypeExecutable)
S
Steven Stewart-Gallus 已提交
859
    }
H
Haitao Li 已提交
860

N
Nick Cameron 已提交
861 862 863 864
    // Only check command line flags if present. If no types are specified by
    // command line, then reuse the empty `base` Vec to hold the types that
    // will be found in crate attributes.
    let mut base = session.opts.crate_types.clone();
865
    if base.len() == 0 {
A
Aaron Turon 已提交
866
        base.extend(attr_types.into_iter());
N
Nick Cameron 已提交
867
        if base.len() == 0 {
868
            base.push(link::default_output_for_target(session));
869
        }
870
        base.sort();
N
Nick Cameron 已提交
871
        base.dedup();
872
    }
873

A
Aaron Turon 已提交
874
    base.into_iter().filter(|crate_type| {
875 876 877
        let res = !link::invalid_output_for_target(session, *crate_type);

        if !res {
J
Jorge Aparicio 已提交
878
            session.warn(&format!("dropping unsupported crate type `{:?}` \
879
                                   for target `{}`",
J
Jorge Aparicio 已提交
880
                                 *crate_type, session.opts.target_triple)[]);
881 882 883 884
        }

        res
    }).collect()
H
Haitao Li 已提交
885 886
}

887 888 889 890 891
pub fn collect_crate_metadata(session: &Session,
                              _attrs: &[ast::Attribute]) -> Vec<String> {
    session.opts.cg.metadata.clone()
}

892
pub fn build_output_filenames(input: &Input,
893 894
                              odir: &Option<Path>,
                              ofile: &Option<Path>,
895
                              attrs: &[ast::Attribute],
E
Eduard Burtescu 已提交
896
                              sess: &Session)
A
Alex Crichton 已提交
897
                           -> OutputFilenames {
898
    match *ofile {
A
Alex Crichton 已提交
899 900 901 902 903 904
        None => {
            // "-" as input file will cause the parser to read from stdin so we
            // have to make up a name
            // We want to toss everything after the final '.'
            let dirpath = match *odir {
                Some(ref d) => d.clone(),
905
                None => Path::new(".")
A
Alex Crichton 已提交
906 907
            };

908
            // If a crate name is present, we use it as the link name
909 910 911 912
            let stem = sess.opts.crate_name.clone().or_else(|| {
                attr::find_crate_name(attrs).map(|n| n.get().to_string())
            }).unwrap_or(input.filestem());

A
Alex Crichton 已提交
913 914 915 916
            OutputFilenames {
                out_directory: dirpath,
                out_filestem: stem,
                single_output_file: None,
917
                extra: sess.opts.cg.extra_filename.clone(),
A
Alex Crichton 已提交
918
            }
H
Haitao Li 已提交
919 920
        }

A
Alex Crichton 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933
        Some(ref out_file) => {
            let ofile = if sess.opts.output_types.len() > 1 {
                sess.warn("ignoring specified output filename because multiple \
                           outputs were requested");
                None
            } else {
                Some(out_file.clone())
            };
            if *odir != None {
                sess.warn("ignoring --out-dir flag due to -o flag.");
            }
            OutputFilenames {
                out_directory: out_file.dir_path(),
934
                out_filestem: out_file.filestem_str().unwrap().to_string(),
A
Alex Crichton 已提交
935
                single_output_file: ofile,
936
                extra: sess.opts.cg.extra_filename.clone(),
A
Alex Crichton 已提交
937
            }
H
Haitao Li 已提交
938
        }
939
    }
H
Haitao Li 已提交
940
}