driver.rs 35.8 KB
Newer Older
N
Nick Cameron 已提交
1
// Copyright 2012-2015 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;
N
Nick Cameron 已提交
30
use super::Compilation;
31

32
use serialize::json;
33

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

N
Nick Cameron 已提交
47 48 49 50
pub fn compile_input(sess: Session,
                     cfg: ast::CrateConfig,
                     input: &Input,
                     outdir: &Option<Path>,
51
                     output: &Option<Path>,
52 53 54 55 56 57 58
                     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);
        }
N
Nick Cameron 已提交
59
        if control.$point.stop == Compilation::Stop {
60 61 62 63
            return;
        }
    })}

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

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

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

94
            (outputs, expanded_crate, id)
N
Nick Cameron 已提交
95
        };
96

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

104
        let mut forest = ast_map::Forest::new(expanded_crate);
105
        let arenas = ty::CtxtArenas::new();
106 107
        let ast_map = assign_node_ids_and_map(&sess, &mut forest);

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

110 111 112 113 114 115 116
        controller_entry_point!(after_write_deps,
                                CompileState::state_after_write_deps(input,
                                                                     &sess,
                                                                     outdir,
                                                                     &ast_map,
                                                                     &id[]));

117 118 119 120 121 122 123 124 125 126 127 128 129
        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));
130 131

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

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

N
Nick Cameron 已提交
142 143 144 145 146 147
        // 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);
148 149 150 151 152 153 154

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

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

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

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

172 173 174
/// 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
J
Joseph Crail 已提交
175
/// collected during compilation.
176 177 178 179 180 181 182 183 184 185 186 187 188
///
/// 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>,
189
    pub after_write_deps: PhaseController<'a>,
190 191 192 193 194 195 196 197 198 199 200
    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(),
201
            after_write_deps:  PhaseController::basic(),
202 203 204 205 206 207 208 209
            after_analysis: PhaseController::basic(),
            after_llvm: PhaseController::basic(),
            make_glob_map: resolve::MakeGlobMap::No,
        }
    }
}

pub struct PhaseController<'a> {
N
Nick Cameron 已提交
210
    pub stop: Compilation,
211 212 213 214 215 216
    pub callback: Box<Fn(CompileState) -> () + 'a>,
}

impl<'a> PhaseController<'a> {
    pub fn basic() -> PhaseController<'a> {
        PhaseController {
N
Nick Cameron 已提交
217
            stop: Compilation::Continue,
218
            callback: box |_| {},
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 284 285
        }
    }
}

/// 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)
        }
    }

286 287 288 289 290 291 292 293 294 295 296 297 298
    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)
        }
    }

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 325 326
    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 已提交
327
pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
A
Alex Crichton 已提交
328
    -> ast::Crate {
M
Murarth 已提交
329 330 331 332 333 334
    // 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();

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

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

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

357
    krate
358
}
H
Haitao Li 已提交
359

360 361
// For continuing compilation after a parsed crate has been
// modified
362

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

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

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

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

C
Corey Richardson 已提交
394
    time(time_passes, "gated macro checking", (), |_| {
395
        let features =
C
Corey Richardson 已提交
396 397 398 399 400 401 402 403 404
            syntax::feature_gate::check_crate_macros(sess.codemap(),
                                                     &sess.parse_sess.span_diagnostic,
                                                     &krate);

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

405
    krate = time(time_passes, "configuration 1", krate, |krate|
406
                 syntax::config::strip_unconfigured_items(sess.diagnostic(), krate));
407

408 409
    krate = time(time_passes, "crate injection", krate, |krate|
                 syntax::std_inject::maybe_inject_crates_ref(krate,
A
Aaron Turon 已提交
410
                                                             sess.opts.alt_std_name.clone()));
411

412
    let mut addl_plugins = Some(addl_plugins);
413 414
    let Plugins { macros, registrars }
        = time(time_passes, "plugin loading", (), |_|
415
               plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
416

417
    let mut registry = Registry::new(sess, &krate);
418

419
    time(time_passes, "plugin registration", registrars, |registrars| {
N
Nick Cameron 已提交
420
        if sess.features.borrow().rustc_diagnostic_macros {
421 422 423 424 425 426 427 428
            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);
        }

429
        for registrar in registrars {
430 431
            registry.args_hidden = Some(registrar.args);
            (registrar.fun)(&mut registry);
432
        }
433
    });
434

435
    let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry;
436

K
Keegan McAllister 已提交
437 438
    {
        let mut ls = sess.lint_store.borrow_mut();
439
        for pass in lint_passes {
K
Keegan McAllister 已提交
440 441
            ls.register_pass(Some(sess), true, pass);
        }
442

443
        for (name, to) in lint_groups {
444 445
            ls.register_group(Some(sess), true, name, to);
        }
K
Keegan McAllister 已提交
446 447 448
    }

    // Lint plugins are registered; now we can process command line flags.
449
    if sess.opts.describe_lints {
K
Keegan McAllister 已提交
450
        super::describe_lints(&*sess.lint_store.borrow(), true);
451 452 453 454 455 456 457
        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();

458 459 460 461 462 463 464
    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.
A
Alex Crichton 已提交
465
            let mut _old_path = OsString::from_str("");
466
            if cfg!(windows) {
467
                _old_path = env::var_os("PATH").unwrap_or(_old_path);
468
                let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
A
Alex Crichton 已提交
469 470
                new_path.extend(env::split_paths(&_old_path));
                env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
471 472
            }
            let cfg = syntax::ext::expand::ExpansionConfig {
473
                crate_name: crate_name.to_string(),
474
                enable_quotes: sess.features.borrow().quote,
475
                recursion_limit: sess.recursion_limit.get(),
476
            };
477
            let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
478 479 480
                                              cfg,
                                              macros,
                                              syntax_exts,
481 482
                                              krate);
            if cfg!(windows) {
A
Alex Crichton 已提交
483
                env::set_var("PATH", &_old_path);
484 485
            }
            ret
486 487 488
        }
    );

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

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

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

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

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

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
    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 }));
536

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

541
    map
542
}
543

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

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

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

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

578 579 580
    // Discard MTWT tables that aren't required past resolution.
    syntax::ext::mtwt::clear_tables();

581
    let named_region_map = time(time_passes, "lifetime resolution", (),
582
                                |_| middle::resolve_lifetime::krate(&sess, krate, &def_map));
583

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

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

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

595 596 597
    time(time_passes, "loop checking", (), |_|
         middle::check_loop::check_crate(&sess, krate));

598 599 600
    time(time_passes, "static item recursion checking", (), |_|
         middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));

601
    let ty_cx = ty::mk_ctxt(sess,
602
                            arenas,
603 604 605 606 607 608
                            def_map,
                            named_region_map,
                            ast_map,
                            freevars,
                            region_map,
                            lang_items,
609
                            stability::Index::new(krate));
610

611
    // passes are timed inside typeck
612
    typeck::check_crate(&ty_cx, trait_map);
B
Brian Anderson 已提交
613

614
    time(time_passes, "check static items", (), |_|
615
         middle::check_static::check_crate(&ty_cx));
616

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

621
    time(time_passes, "const checking", (), |_|
622
         middle::check_const::check_crate(&ty_cx));
B
Brian Anderson 已提交
623

624
    let maps = (external_exports, last_private_map);
A
Alex Crichton 已提交
625 626
    let (exported_items, public_items) =
            time(time_passes, "privacy checking", maps, |(a, b)|
627
                 rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
B
Brian Anderson 已提交
628

629 630
    // Do not move this check past lint
    time(time_passes, "stability index", (), |_|
631
         ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
632

633
    time(time_passes, "intrinsic checking", (), |_|
634
         middle::intrinsicck::check_crate(&ty_cx));
635

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

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

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

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

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

651 652 653 654 655 656
    // 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 已提交
657

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

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

668 669 670 671
    let ref lib_features_used =
        time(time_passes, "stability checking", (), |_|
             stability::check_unstable_api_usage(&ty_cx));

672 673
    time(time_passes, "unused lib feature checking", (), |_|
         stability::check_unused_or_stable_features(
674 675
             &ty_cx.sess, lib_features_used));

676
    time(time_passes, "lint checking", (), |_|
677
         lint::check_crate(&ty_cx, &exported_items));
678

B
Brian Anderson 已提交
679
    // The above three passes generate errors w/o aborting
680 681
    ty_cx.sess.abort_if_errors();

682
    ty::CrateAnalysis {
683
        export_map: export_map,
684
        ty_cx: ty_cx,
685
        exported_items: exported_items,
A
Alex Crichton 已提交
686
        public_items: public_items,
687
        reachable: reachable_map,
688
        name: name,
689
        glob_map: glob_map,
690 691
    }
}
J
James Miller 已提交
692

693 694
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
695 696
pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
                                       -> (ty::ctxt<'tcx>, trans::CrateTranslation) {
697
    let time_passes = analysis.ty_cx.sess.time_passes();
698 699 700 701 702

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

    // Option dance to work around the lack of stack once closures.
703
    time(time_passes, "translation", analysis, |analysis|
704
         trans::trans_crate(analysis))
705 706 707 708
}

/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
E
Eduard Burtescu 已提交
709
pub fn phase_5_run_llvm_passes(sess: &Session,
710
                               trans: &trans::CrateTranslation,
711
                               outputs: &OutputFilenames) {
712
    if sess.opts.cg.no_integrated_as {
713
        let output_type = config::OutputTypeAssembly;
714

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

718
        write::run_assembler(sess, outputs);
V
Vadim Chugunov 已提交
719

720
        // Remove assembly source, unless --save-temps was specified
721
        if !sess.opts.cg.save_temps {
722
            fs::unlink(&outputs.temp_path(config::OutputTypeAssembly)).unwrap();
V
Vadim Chugunov 已提交
723
        }
724
    } else {
725
        time(sess.time_passes(), "LLVM passes", (), |_|
726 727
            write::run_passes(sess,
                              trans,
J
Jorge Aparicio 已提交
728
                              &sess.opts.output_types[],
729
                              outputs));
730
    }
731 732

    sess.abort_if_errors();
733
}
H
Haitao Li 已提交
734

735 736
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
E
Eduard Burtescu 已提交
737
pub fn phase_6_link_output(sess: &Session,
738
                           trans: &trans::CrateTranslation,
739
                           outputs: &OutputFilenames) {
740
    let old_path = env::var_os("PATH").unwrap_or(OsString::from_str(""));
741
    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
A
Alex Crichton 已提交
742 743
    new_path.extend(env::split_paths(&old_path));
    env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
744

745
    time(sess.time_passes(), "linking", (), |_|
746
         link::link_binary(sess,
747
                           trans,
A
Alex Crichton 已提交
748
                           outputs,
J
Jorge Aparicio 已提交
749
                           &trans.link.crate_name[]));
750

A
Alex Crichton 已提交
751
    env::set_var("PATH", &old_path);
752 753
}

754 755 756 757 758 759
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 已提交
760
fn write_out_deps(sess: &Session,
A
Alex Crichton 已提交
761 762
                  input: &Input,
                  outputs: &OutputFilenames,
763
                  id: &str) {
764

765
    let mut out_filenames = Vec::new();
766
    for output_type in &sess.opts.output_types {
A
Alex Crichton 已提交
767 768
        let file = outputs.path(*output_type);
        match *output_type {
769
            config::OutputTypeExe => {
770
                for output in &*sess.crate_types.borrow() {
771 772
                    let p = link::filename_for_input(sess, *output,
                                                     id, &file);
A
Alex Crichton 已提交
773 774 775 776 777 778
                    out_filenames.push(p);
                }
            }
            _ => { out_filenames.push(file); }
        }
    }
779

A
Alex Crichton 已提交
780 781
    // Write out dependency rules to the dep-info file if requested with
    // --dep-info
782 783 784
    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 已提交
785 786
        // Use default filename: crate source filename with extension replaced
        // by ".d"
787
        (true, None) => match *input {
788 789
            Input::File(..) => outputs.with_extension("d"),
            Input::Str(..) => {
A
Alex Crichton 已提交
790 791
                sess.warn("can not write --dep-info without a filename \
                           when compiling stdin.");
792
                return
793 794
            },
        },
795
        _ => return,
796
    };
797

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

    match result {
        Ok(()) => {}
        Err(e) => {
J
Jorge Aparicio 已提交
816 817
            sess.fatal(&format!("error writing dependencies to `{}`: {}",
                               deps_filename.display(), e)[]);
818
        }
819
    }
820 821
}

N
Nick Cameron 已提交
822 823
pub fn collect_crate_types(session: &Session,
                           attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
824 825 826 827
    // 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() {
828
                Some(ref n) if *n == "rlib" => {
829 830
                    Some(config::CrateTypeRlib)
                }
831
                Some(ref n) if *n == "dylib" => {
832 833
                    Some(config::CrateTypeDylib)
                }
834
                Some(ref n) if *n == "lib" => {
835 836
                    Some(config::default_lib_output())
                }
837
                Some(ref n) if *n == "staticlib" => {
838 839
                    Some(config::CrateTypeStaticlib)
                }
840
                Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
841
                Some(_) => {
A
Aaron Turon 已提交
842
                    session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
843 844 845
                                     ast::CRATE_NODE_ID,
                                     a.span,
                                     "invalid `crate_type` \
846
                                      value".to_string());
847 848 849
                    None
                }
                _ => {
A
Aaron Turon 已提交
850
                    session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
851 852 853
                                     ast::CRATE_NODE_ID,
                                     a.span,
                                     "`crate_type` requires a \
854
                                      value".to_string());
855 856 857 858 859 860 861 862
                    None
                }
            }
        } else {
            None
        }
    }).collect();

N
Nick Cameron 已提交
863 864 865 866
    // 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 已提交
867
    }
H
Haitao Li 已提交
868

N
Nick Cameron 已提交
869 870 871 872
    // 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();
873
    if base.len() == 0 {
A
Aaron Turon 已提交
874
        base.extend(attr_types.into_iter());
N
Nick Cameron 已提交
875
        if base.len() == 0 {
876
            base.push(link::default_output_for_target(session));
877
        }
878
        base.sort();
N
Nick Cameron 已提交
879
        base.dedup();
880
    }
881

A
Aaron Turon 已提交
882
    base.into_iter().filter(|crate_type| {
883 884 885
        let res = !link::invalid_output_for_target(session, *crate_type);

        if !res {
886
            session.warn(&format!("dropping unsupported crate type `{}` \
887
                                   for target `{}`",
J
Jorge Aparicio 已提交
888
                                 *crate_type, session.opts.target_triple)[]);
889 890 891 892
        }

        res
    }).collect()
H
Haitao Li 已提交
893 894
}

895 896 897 898 899
pub fn collect_crate_metadata(session: &Session,
                              _attrs: &[ast::Attribute]) -> Vec<String> {
    session.opts.cg.metadata.clone()
}

900
pub fn build_output_filenames(input: &Input,
901 902
                              odir: &Option<Path>,
                              ofile: &Option<Path>,
903
                              attrs: &[ast::Attribute],
E
Eduard Burtescu 已提交
904
                              sess: &Session)
A
Alex Crichton 已提交
905
                           -> OutputFilenames {
906
    match *ofile {
A
Alex Crichton 已提交
907 908 909 910 911 912
        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(),
913
                None => Path::new(".")
A
Alex Crichton 已提交
914 915
            };

916
            // If a crate name is present, we use it as the link name
917
            let stem = sess.opts.crate_name.clone().or_else(|| {
918
                attr::find_crate_name(attrs).map(|n| n.to_string())
919 920
            }).unwrap_or(input.filestem());

A
Alex Crichton 已提交
921 922 923 924
            OutputFilenames {
                out_directory: dirpath,
                out_filestem: stem,
                single_output_file: None,
925
                extra: sess.opts.cg.extra_filename.clone(),
A
Alex Crichton 已提交
926
            }
H
Haitao Li 已提交
927 928
        }

A
Alex Crichton 已提交
929 930 931 932 933 934 935 936 937 938 939 940 941
        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(),
942
                out_filestem: out_file.filestem_str().unwrap().to_string(),
A
Alex Crichton 已提交
943
                single_output_file: ofile,
944
                extra: sess.opts.cg.extra_filename.clone(),
A
Alex Crichton 已提交
945
            }
H
Haitao Li 已提交
946
        }
947
    }
H
Haitao Li 已提交
948
}