driver.rs 40.4 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 12
use rustc::front;
use rustc::front::map as hir_map;
13
use rustc_mir as mir;
14
use rustc::session::Session;
15
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
16
use rustc::session::search_paths::PathKind;
17
use rustc::lint;
18
use rustc::metadata;
19
use rustc::metadata::creader::LocalCrateReader;
20
use rustc::middle::{stability, ty, reachable};
21 22 23 24 25
use rustc::middle::dependency_format;
use rustc::middle;
use rustc::plugin::registry::Registry;
use rustc::plugin;
use rustc::util::common::time;
26
use rustc_borrowck as borrowck;
27
use rustc_resolve as resolve;
28 29 30
use rustc_trans::back::link;
use rustc_trans::back::write;
use rustc_trans::trans;
N
Niko Matsakis 已提交
31
use rustc_typeck as typeck;
32
use rustc_privacy;
33
use rustc_front::hir;
N
Nick Cameron 已提交
34
use rustc_front::lowering::{lower_crate, LoweringContext};
N
Nick Cameron 已提交
35
use super::Compilation;
36

37
use serialize::json;
38

39
use std::collections::HashMap;
A
Alex Crichton 已提交
40
use std::env;
41
use std::ffi::{OsString, OsStr};
A
Alex Crichton 已提交
42 43 44
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
45
use syntax::ast::{self, NodeIdAssigner};
46
use syntax::attr;
47
use syntax::attr::AttrMetaMethods;
48
use syntax::diagnostics;
49
use syntax::feature_gate::UnstableFeatures;
50
use syntax::fold::Folder;
51
use syntax::parse;
J
John Clements 已提交
52
use syntax::parse::token;
53
use syntax;
H
Haitao Li 已提交
54

N
Nick Cameron 已提交
55 56 57
pub fn compile_input(sess: Session,
                     cfg: ast::CrateConfig,
                     input: &Input,
A
Alex Crichton 已提交
58 59
                     outdir: &Option<PathBuf>,
                     output: &Option<PathBuf>,
60 61
                     addl_plugins: Option<Vec<String>>,
                     control: CompileController) {
62 63 64 65 66
    macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: expr) => ({
        let state = $make_state;
        (control.$point.callback)(state);

        $tsess.abort_if_errors();
N
Nick Cameron 已提交
67
        if control.$point.stop == Compilation::Stop {
68 69 70 71
            return;
        }
    })}

N
Nick Cameron 已提交
72 73 74
    // 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
75
    let result = {
76
        let (outputs, expanded_crate, id) = {
N
Nick Cameron 已提交
77
            let krate = phase_1_parse_input(&sess, cfg, input);
78 79

            controller_entry_point!(after_parse,
80
                                    sess,
81 82 83 84 85
                                    CompileState::state_after_parse(input,
                                                                    &sess,
                                                                    outdir,
                                                                    &krate));

N
Nick Cameron 已提交
86 87 88
            let outputs = build_output_filenames(input,
                                                 outdir,
                                                 output,
89
                                                 &krate.attrs,
N
Nick Cameron 已提交
90
                                                 &sess);
91
            let id = link::find_crate_name(Some(&sess),
92
                                           &krate.attrs,
93
                                           input);
94
            let expanded_crate
95 96
                = match phase_2_configure_and_expand(&sess,
                                                     krate,
97
                                                     &id[..],
98
                                                     addl_plugins) {
99
                    None => return,
100
                    Some(k) => k
101 102
                };

103
            (outputs, expanded_crate, id)
N
Nick Cameron 已提交
104
        };
105

106
        controller_entry_point!(after_expand,
107
                                sess,
108 109 110 111
                                CompileState::state_after_expand(input,
                                                                 &sess,
                                                                 outdir,
                                                                 &expanded_crate,
112
                                                                 &id[..]));
113

114 115
        let expanded_crate = assign_node_ids(&sess, expanded_crate);
        // Lower ast -> hir.
N
Nick Cameron 已提交
116
        let lcx = LoweringContext::new(&sess, Some(&expanded_crate));
117 118
        let mut hir_forest = time(sess.time_passes(),
                                  "lowering ast -> hir",
N
Nick Cameron 已提交
119
                                  || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate)));
120
        let arenas = ty::CtxtArenas::new();
121
        let ast_map = make_map(&sess, &mut hir_forest);
122

123
        write_out_deps(&sess, &outputs, &id);
N
Nick Cameron 已提交
124

125
        controller_entry_point!(after_write_deps,
126
                                sess,
127 128 129 130
                                CompileState::state_after_write_deps(input,
                                                                     &sess,
                                                                     outdir,
                                                                     &ast_map,
131
                                                                     &expanded_crate,
132
                                                                     &ast_map.krate(),
N
Nick Cameron 已提交
133 134
                                                                     &id[..],
                                                                     &lcx));
135

S
Seo Sanghyeon 已提交
136 137 138 139
        time(sess.time_passes(), "attribute checking", || {
            front::check_attr::check_crate(&sess, &expanded_crate);
        });

N
Nick Cameron 已提交
140 141 142
        time(sess.time_passes(), "early lint checks", || {
            lint::check_ast_crate(&sess, &expanded_crate)
        });
143

144
        phase_3_run_analysis_passes(&sess,
145 146
                                    ast_map,
                                    &arenas,
147
                                    &id,
148 149 150 151 152 153 154
                                    control.make_glob_map,
                                    |tcx, analysis| {

            {
                let state = CompileState::state_after_analysis(input,
                                                               &tcx.sess,
                                                               outdir,
155
                                                               &expanded_crate,
156 157
                                                               tcx.map.krate(),
                                                               &analysis,
N
Nick Cameron 已提交
158
                                                               tcx,
159 160
                                                               &lcx,
                                                               &id);
161 162 163 164 165 166 167
                (control.after_analysis.callback)(state);

                tcx.sess.abort_if_errors();
                if control.after_analysis.stop == Compilation::Stop {
                    return Err(());
                }
            }
N
Nick Cameron 已提交
168

169 170 171 172 173 174 175 176 177 178 179 180 181
            if log_enabled!(::log::INFO) {
                println!("Pre-trans");
                tcx.print_debug_stats();
            }
            let trans = phase_4_translate_to_llvm(tcx, analysis);

            if log_enabled!(::log::INFO) {
                println!("Post-trans");
                tcx.print_debug_stats();
            }

            // Discard interned strings as they are no longer required.
            token::get_ident_interner().clear();
182

183 184 185
            Ok((outputs, trans))
        })
    };
N
Nick Cameron 已提交
186

187 188 189 190
    let (outputs, trans) = if let Ok(out) = result {
        out
    } else {
        return;
N
Nick Cameron 已提交
191
    };
192

N
Nick Cameron 已提交
193
    phase_5_run_llvm_passes(&sess, &trans, &outputs);
194 195

    controller_entry_point!(after_llvm,
196
                            sess,
197 198 199 200 201
                            CompileState::state_after_llvm(input,
                                                           &sess,
                                                           outdir,
                                                           &trans));

N
Nick Cameron 已提交
202
    phase_6_link_output(&sess, &trans, &outputs);
203
}
H
Haitao Li 已提交
204

S
Steve Klabnik 已提交
205 206
/// The name used for source code that doesn't originate in a file
/// (e.g. source from stdin or a string)
207
pub fn anon_src() -> String {
208
    "<anon>".to_string()
P
Patrick Walton 已提交
209
}
210

211
pub fn source_name(input: &Input) -> String {
212
    match *input {
E
Eduard Burtescu 已提交
213
        // FIXME (#9639): This needs to handle non-utf8 paths
A
Alex Crichton 已提交
214
        Input::File(ref ifile) => ifile.to_str().unwrap().to_string(),
215
        Input::Str(_) => anon_src()
216 217 218
    }
}

219 220 221
/// 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 已提交
222
/// collected during compilation.
223 224 225 226 227 228 229 230 231 232 233 234 235
///
/// 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>,
236
    pub after_write_deps: PhaseController<'a>,
237 238 239 240 241 242 243 244 245 246 247
    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(),
248
            after_write_deps:  PhaseController::basic(),
249 250 251 252 253 254 255 256
            after_analysis: PhaseController::basic(),
            after_llvm: PhaseController::basic(),
            make_glob_map: resolve::MakeGlobMap::No,
        }
    }
}

pub struct PhaseController<'a> {
N
Nick Cameron 已提交
257
    pub stop: Compilation,
258 259 260 261 262 263
    pub callback: Box<Fn(CompileState) -> () + 'a>,
}

impl<'a> PhaseController<'a> {
    pub fn basic() -> PhaseController<'a> {
        PhaseController {
N
Nick Cameron 已提交
264
            stop: Compilation::Continue,
265
            callback: box |_| {},
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
        }
    }
}

/// 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>,
282 283
    pub hir_crate: Option<&'a hir::Crate>,
    pub ast_map: Option<&'a hir_map::Map<'ast>>,
284
    pub analysis: Option<&'a ty::CrateAnalysis<'a>>,
285
    pub tcx: Option<&'a ty::ctxt<'tcx>>,
N
Nick Cameron 已提交
286
    pub lcx: Option<&'a LoweringContext<'a>>,
287 288 289 290 291 292
    pub trans: Option<&'a trans::CrateTranslation>,
}

impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
    fn empty(input: &'a Input,
             session: &'a Session,
A
Alex Crichton 已提交
293
             out_dir: &'a Option<PathBuf>)
294 295 296 297
             -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            input: input,
            session: session,
A
Alex Crichton 已提交
298
            out_dir: out_dir.as_ref().map(|s| &**s),
299 300 301 302 303
            cfg: None,
            krate: None,
            crate_name: None,
            output_filenames: None,
            expanded_crate: None,
304
            hir_crate: None,
305 306 307
            ast_map: None,
            analysis: None,
            tcx: None,
N
Nick Cameron 已提交
308
            lcx: None,
309 310 311 312 313 314
            trans: None,
        }
    }

    fn state_after_parse(input: &'a Input,
                         session: &'a Session,
A
Alex Crichton 已提交
315
                         out_dir: &'a Option<PathBuf>,
316 317 318 319 320 321 322 323 324 325
                         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,
A
Alex Crichton 已提交
326
                          out_dir: &'a Option<PathBuf>,
327 328 329 330 331 332 333 334 335 336
                          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)
        }
    }

337 338
    fn state_after_write_deps(input: &'a Input,
                              session: &'a Session,
A
Alex Crichton 已提交
339
                              out_dir: &'a Option<PathBuf>,
340 341 342
                              ast_map: &'a hir_map::Map<'ast>,
                              krate: &'a ast::Crate,
                              hir_crate: &'a hir::Crate,
N
Nick Cameron 已提交
343
                              crate_name: &'a str,
N
Nick Cameron 已提交
344
                              lcx: &'a LoweringContext<'a>)
345 346 347 348
                              -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            crate_name: Some(crate_name),
            ast_map: Some(ast_map),
349 350
            krate: Some(krate),
            hir_crate: Some(hir_crate),
N
Nick Cameron 已提交
351
            lcx: Some(lcx),
352 353 354 355
            .. CompileState::empty(input, session, out_dir)
        }
    }

356 357
    fn state_after_analysis(input: &'a Input,
                            session: &'a Session,
A
Alex Crichton 已提交
358
                            out_dir: &'a Option<PathBuf>,
359 360
                            krate: &'a ast::Crate,
                            hir_crate: &'a hir::Crate,
361
                            analysis: &'a ty::CrateAnalysis,
N
Nick Cameron 已提交
362
                            tcx: &'a ty::ctxt<'tcx>,
363 364
                            lcx: &'a LoweringContext<'a>,
                            crate_name: &'a str)
365 366 367 368
                            -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            analysis: Some(analysis),
            tcx: Some(tcx),
369 370
            krate: Some(krate),
            hir_crate: Some(hir_crate),
N
Nick Cameron 已提交
371
            lcx: Some(lcx),
372
            crate_name: Some(crate_name),
373 374 375 376 377 378 379
            .. CompileState::empty(input, session, out_dir)
        }
    }


    fn state_after_llvm(input: &'a Input,
                        session: &'a Session,
A
Alex Crichton 已提交
380
                        out_dir: &'a Option<PathBuf>,
381 382 383 384 385 386 387 388 389
                        trans: &'a trans::CrateTranslation)
                        -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            trans: Some(trans),
            .. CompileState::empty(input, session, out_dir)
        }
    }
}

E
Eduard Burtescu 已提交
390
pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
A
Alex Crichton 已提交
391
    -> ast::Crate {
M
Murarth 已提交
392 393 394 395 396 397
    // 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();

398
    let krate = time(sess.time_passes(), "parsing", || {
399
        match *input {
400
            Input::File(ref file) => {
E
Eduard Burtescu 已提交
401
                parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
402
            }
403
            Input::Str(ref src) => {
404 405
                parse::parse_crate_from_source_str(anon_src().to_string(),
                                                   src.to_string(),
406
                                                   cfg.clone(),
E
Eduard Burtescu 已提交
407
                                                   &sess.parse_sess)
408 409
            }
        }
410 411
    });

412
    if sess.opts.debugging_opts.ast_json_noexpand {
413
        println!("{}", json::as_json(&krate));
414 415
    }

S
Seo Sanghyeon 已提交
416
    if let Some(ref s) = sess.opts.show_span {
417
        syntax::show_span::run(sess.diagnostic(), s, &krate);
418 419
    }

420
    krate
421
}
H
Haitao Li 已提交
422

423 424
// For continuing compilation after a parsed crate has been
// modified
425

426
/// Run the "early phases" of the compiler: initial `cfg` processing,
B
Brian Anderson 已提交
427
/// loading compiler plugins (including those from `addl_plugins`),
428 429 430
/// 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.
431 432
///
/// Returns `None` if we're aborting after handling -W help.
E
Eduard Burtescu 已提交
433
pub fn phase_2_configure_and_expand(sess: &Session,
434
                                    mut krate: ast::Crate,
435
                                    crate_name: &str,
436
                                    addl_plugins: Option<Vec<String>>)
437
                                    -> Option<ast::Crate> {
438
    let time_passes = sess.time_passes();
H
Haitao Li 已提交
439

440 441
    // strip before anything else because crate metadata may use #[cfg_attr]
    // and so macros can depend on configuration variables, such as
442
    //
443
    //   #[macro_use] #[cfg(foo)]
444 445 446
    //   mod bar { macro_rules! baz!(() => {{}}) }
    //
    // baz! should not use this definition unless foo is enabled.
447

448 449 450 451
    let mut feature_gated_cfgs = vec![];
    krate = time(time_passes, "configuration 1", ||
                 syntax::config::strip_unconfigured_items(sess.diagnostic(), krate,
                                                          &mut feature_gated_cfgs));
452

453 454 455 456 457
    *sess.crate_types.borrow_mut() =
        collect_crate_types(sess, &krate.attrs);
    *sess.crate_metadata.borrow_mut() =
        collect_crate_metadata(sess, &krate.attrs);

458
    time(time_passes, "recursion limit", || {
459 460 461
        middle::recursion_limit::update_recursion_limit(sess, &krate);
    });

462
    time(time_passes, "gated macro checking", || {
463
        let features =
C
Corey Richardson 已提交
464 465 466 467 468 469 470 471 472
            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();
    });

473

474
    krate = time(time_passes, "crate injection", ||
475
                 syntax::std_inject::maybe_inject_crates_ref(krate,
A
Aaron Turon 已提交
476
                                                             sess.opts.alt_std_name.clone()));
477

478
    let macros = time(time_passes, "macro loading", ||
479 480
        metadata::macro_import::read_macro_defs(sess, &krate));

481
    let mut addl_plugins = Some(addl_plugins);
482
    let registrars = time(time_passes, "plugin loading", ||
483
        plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
484

485
    let mut registry = Registry::new(sess, &krate);
486

487
    time(time_passes, "plugin registration", || {
N
Nick Cameron 已提交
488
        if sess.features.borrow().rustc_diagnostic_macros {
489 490 491 492 493 494 495 496
            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);
        }

497
        for registrar in registrars {
498 499
            registry.args_hidden = Some(registrar.args);
            (registrar.fun)(&mut registry);
500
        }
501
    });
502

N
Nick Cameron 已提交
503
    let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
504
                   llvm_passes, attributes, .. } = registry;
505

K
Keegan McAllister 已提交
506 507
    {
        let mut ls = sess.lint_store.borrow_mut();
N
Nick Cameron 已提交
508 509 510 511 512
        for pass in early_lint_passes {
            ls.register_early_pass(Some(sess), true, pass);
        }
        for pass in late_lint_passes {
            ls.register_late_pass(Some(sess), true, pass);
K
Keegan McAllister 已提交
513
        }
514

515
        for (name, to) in lint_groups {
516 517
            ls.register_group(Some(sess), true, name, to);
        }
518 519

        *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
520
        *sess.plugin_attributes.borrow_mut() = attributes.clone();
K
Keegan McAllister 已提交
521 522 523
    }

    // Lint plugins are registered; now we can process command line flags.
524
    if sess.opts.describe_lints {
K
Keegan McAllister 已提交
525
        super::describe_lints(&*sess.lint_store.borrow(), true);
526 527 528 529 530 531 532
        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();

533 534 535 536 537 538 539 540 541 542 543 544 545
    krate = time(time_passes, "expansion", || {
        // 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.
        let mut _old_path = OsString::new();
        if cfg!(windows) {
            _old_path = env::var_os("PATH").unwrap_or(_old_path);
            let mut new_path = sess.host_filesearch(PathKind::All)
                                   .get_dylib_search_paths();
            new_path.extend(env::split_paths(&_old_path));
            env::set_var("PATH", &env::join_paths(new_path).unwrap());
546
        }
547 548 549 550 551 552 553 554 555 556 557
        let features = sess.features.borrow();
        let cfg = syntax::ext::expand::ExpansionConfig {
            crate_name: crate_name.to_string(),
            features: Some(&features),
            recursion_limit: sess.recursion_limit.get(),
            trace_mac: sess.opts.debugging_opts.trace_macros,
        };
        let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
                                          cfg,
                                          macros,
                                          syntax_exts,
558
                                          &mut feature_gated_cfgs,
559 560 561 562 563 564
                                          krate);
        if cfg!(windows) {
            env::set_var("PATH", &_old_path);
        }
        ret
    });
565

566 567 568 569
    // Needs to go *after* expansion to be able to check the results
    // of macro expansion.  This runs before #[cfg] to try to catch as
    // much as possible (e.g. help the programmer avoid platform
    // specific differences)
570
    time(time_passes, "complete gated feature checking 1", || {
B
Brian Anderson 已提交
571
        let features =
572
            syntax::feature_gate::check_crate(sess.codemap(),
573
                                              &sess.parse_sess.span_diagnostic,
574 575
                                              &krate, &attributes,
                                              sess.opts.unstable_features);
576
        *sess.features.borrow_mut() = features;
C
Corey Richardson 已提交
577 578 579
        sess.abort_if_errors();
    });

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

582
    // strip again, in case expansion added anything with a #[cfg].
583
    krate = time(time_passes, "configuration 2", ||
584 585 586 587 588 589 590 591 592 593 594
                 syntax::config::strip_unconfigured_items(sess.diagnostic(), krate,
                                                          &mut feature_gated_cfgs));

    time(time_passes, "gated configuration checking", || {
        let features = sess.features.borrow();
        feature_gated_cfgs.sort();
        feature_gated_cfgs.dedup();
        for cfg in &feature_gated_cfgs {
            cfg.check_and_emit(sess.diagnostic(), &features);
        }
    });
595

596
    krate = time(time_passes, "maybe building test harness", ||
N
Nick Cameron 已提交
597 598 599 600
                 syntax::test::modify_for_testing(&sess.parse_sess,
                                                  &sess.opts.cfg,
                                                  krate,
                                                  sess.diagnostic()));
601

602
    krate = time(time_passes, "prelude injection", ||
603
                 syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate));
B
Brian Anderson 已提交
604

605 606
    time(time_passes, "checking that all macro invocations are gone", ||
         syntax::ext::expand::check_for_macros(&sess.parse_sess, &krate));
607

608 609 610
    time(time_passes, "checking for inline asm in case the target doesn't support it", ||
         middle::check_no_asm::check_crate(sess, &krate));

611 612 613
    // One final feature gating of the true AST that gets compiled
    // later, to make sure we've got everything (e.g. configuration
    // can insert new attributes via `cfg_attr`)
614
    time(time_passes, "complete gated feature checking 2", || {
615 616 617
        let features =
            syntax::feature_gate::check_crate(sess.codemap(),
                                              &sess.parse_sess.span_diagnostic,
618 619
                                              &krate, &attributes,
                                              sess.opts.unstable_features);
620 621 622 623
        *sess.features.borrow_mut() = features;
        sess.abort_if_errors();
    });

624 625 626
    Some(krate)
}

627 628
pub fn assign_node_ids(sess: &Session,
                       krate: ast::Crate) -> ast::Crate {
629 630 631 632
    struct NodeIdAssigner<'a> {
        sess: &'a Session
    }

633 634
    impl<'a> Folder for NodeIdAssigner<'a> {
        fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
635 636 637 638 639
            assert_eq!(old_id, ast::DUMMY_NODE_ID);
            self.sess.next_node_id()
        }
    }

640 641 642
    let krate = time(sess.time_passes(),
                     "assigning node ids",
                     || NodeIdAssigner { sess: sess }.fold_crate(krate));
643

644
    if sess.opts.debugging_opts.ast_json {
645
        println!("{}", json::as_json(&krate));
646 647
    }

648 649 650 651 652 653 654 655 656 657 658
    krate
}

pub fn make_map<'ast>(sess: &Session,
                      forest: &'ast mut front::map::Forest)
                      -> front::map::Map<'ast> {
    // Construct the 'ast'-map
    let map = time(sess.time_passes(),
                   "indexing hir",
                   move || front::map::map_crate(forest));

659
    map
660
}
661

662 663 664
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
665
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
666
                                               ast_map: front::map::Map<'tcx>,
667
                                               arenas: &'tcx ty::CtxtArenas<'tcx>,
668
                                               name: &str,
669 670
                                               make_glob_map: resolve::MakeGlobMap,
                                               f: F)
671
                                               -> R
J
Jared Roesch 已提交
672
                                               where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>,
673
                                                                       ty::CrateAnalysis) -> R
674
{
675
    let time_passes = sess.time_passes();
676
    let krate = ast_map.krate();
677

678
    time(time_passes, "external crate/lib resolution", ||
679
         LocalCrateReader::new(sess, &ast_map).read_crates(krate));
B
Brian Anderson 已提交
680

681
    let lang_items = time(time_passes, "language item collection", ||
682
                          middle::lang_items::collect_language_items(&sess, &ast_map));
683

N
Nick Cameron 已提交
684
    let resolve::CrateMap {
685 686
        def_map,
        freevars,
687
        export_map,
688 689
        trait_map,
        external_exports,
690
        glob_map,
691
    } =
692
        time(time_passes, "resolution",
693
             || resolve::resolve_crate(sess, &ast_map, make_glob_map));
B
Brian Anderson 已提交
694

695
    // Discard MTWT tables that aren't required past resolution.
696 697 698
    if !sess.opts.debugging_opts.keep_mtwt_tables {
        syntax::ext::mtwt::clear_tables();
    }
699

700
    let named_region_map = time(time_passes, "lifetime resolution",
701
                                || middle::resolve_lifetime::krate(sess, krate, &def_map));
702

703
    time(time_passes, "looking for entry point",
704
         || middle::entry::find_entry_point(sess, &ast_map));
B
Brian Anderson 已提交
705

706
    sess.plugin_registrar_fn.set(
707
        time(time_passes, "looking for plugin registrar", ||
708
            plugin::build::find_plugin_registrar(
709
                sess.diagnostic(), krate)));
710

711
    let region_map = time(time_passes, "region resolution", ||
712
                          middle::region::resolve_crate(sess, krate));
713

714
    time(time_passes, "loop checking", ||
715
         middle::check_loop::check_crate(sess, krate));
716

717
    time(time_passes, "static item recursion checking", ||
718
         middle::check_static_recursion::check_crate(sess, krate, &def_map, &ast_map));
719

720 721 722 723 724 725 726 727 728 729
    ty::ctxt::create_and_enter(sess,
                               arenas,
                               def_map,
                               named_region_map,
                               ast_map,
                               freevars,
                               region_map,
                               lang_items,
                               stability::Index::new(krate),
                               |tcx| {
730 731 732 733

        // passes are timed inside typeck
        typeck::check_crate(tcx, trait_map);

734
        time(time_passes, "const checking", ||
735 736 737
            middle::check_const::check_crate(tcx));

        let (exported_items, public_items) =
738
                time(time_passes, "privacy checking", ||
739 740 741
                    rustc_privacy::check_crate(tcx, &export_map, external_exports));

        // Do not move this check past lint
742
        time(time_passes, "stability index", ||
743 744
            tcx.stability.borrow_mut().build(tcx, krate, &public_items));

745
        time(time_passes, "intrinsic checking", ||
746 747
            middle::intrinsicck::check_crate(tcx));

748
        time(time_passes, "effect checking", ||
749 750
            middle::effect::check_crate(tcx));

751
        time(time_passes, "match checking", ||
752 753
            middle::check_match::check_crate(tcx));

754 755 756 757 758 759 760 761 762 763 764 765
        match tcx.sess.opts.unstable_features {
            UnstableFeatures::Disallow => {
                // use this as a shorthand for beta/stable, and skip
                // MIR construction there until known regressions are
                // addressed
            }
            UnstableFeatures::Allow | UnstableFeatures::Cheat => {
                let _mir_map =
                    time(time_passes, "MIR dump", ||
                            mir::mir_map::build_mir_for_crate(tcx));
            }
        }
766

767
        time(time_passes, "liveness checking", ||
768 769
            middle::liveness::check_crate(tcx));

770
        time(time_passes, "borrow checking", ||
771 772
            borrowck::check_crate(tcx));

773
        time(time_passes, "rvalue checking", ||
774 775 776 777 778 779 780 781 782 783
            middle::check_rvalues::check_crate(tcx, krate));

        // 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
        tcx.sess.abort_if_errors();

        let reachable_map =
784
            time(time_passes, "reachability checking", ||
785 786
                reachable::find_reachable(tcx, &exported_items));

787
        time(time_passes, "death checking", || {
788 789 790 791 792 793
            middle::dead::check_crate(tcx,
                                      &exported_items,
                                      &reachable_map)
        });

        let ref lib_features_used =
794
            time(time_passes, "stability checking", ||
795 796
                stability::check_unstable_api_usage(tcx));

797
        time(time_passes, "unused lib feature checking", ||
798 799 800
            stability::check_unused_or_stable_features(
                &tcx.sess, lib_features_used));

801
        time(time_passes, "lint checking", ||
802
            lint::check_crate(tcx, krate, &exported_items));
803 804 805 806 807 808 809 810 811 812 813 814

        // The above three passes generate errors w/o aborting
        tcx.sess.abort_if_errors();

        f(tcx, ty::CrateAnalysis {
            export_map: export_map,
            exported_items: exported_items,
            public_items: public_items,
            reachable: reachable_map,
            name: name,
            glob_map: glob_map,
        })
815
    })
816
}
J
James Miller 已提交
817

818 819
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
820 821 822
pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis)
                                 -> trans::CrateTranslation {
    let time_passes = tcx.sess.time_passes();
823

824 825
    time(time_passes, "resolving dependency formats", ||
         dependency_format::calculate(&tcx.sess));
826 827

    // Option dance to work around the lack of stack once closures.
828
    time(time_passes, "translation", move ||
829
         trans::trans_crate(tcx, analysis))
830 831 832 833
}

/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
E
Eduard Burtescu 已提交
834
pub fn phase_5_run_llvm_passes(sess: &Session,
835
                               trans: &trans::CrateTranslation,
836
                               outputs: &OutputFilenames) {
837
    if sess.opts.cg.no_integrated_as {
838 839
        let mut map = HashMap::new();
        map.insert(OutputType::Assembly, None);
840
        time(sess.time_passes(), "LLVM passes", ||
841
            write::run_passes(sess, trans, &map, outputs));
842

843
        write::run_assembler(sess, outputs);
V
Vadim Chugunov 已提交
844

845
        // Remove assembly source, unless --save-temps was specified
846
        if !sess.opts.cg.save_temps {
847
            fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap();
V
Vadim Chugunov 已提交
848
        }
849
    } else {
850
        time(sess.time_passes(), "LLVM passes", ||
851 852
            write::run_passes(sess,
                              trans,
853
                              &sess.opts.output_types,
854
                              outputs));
855
    }
856 857

    sess.abort_if_errors();
858
}
H
Haitao Li 已提交
859

860 861
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
E
Eduard Burtescu 已提交
862
pub fn phase_6_link_output(sess: &Session,
863
                           trans: &trans::CrateTranslation,
864
                           outputs: &OutputFilenames) {
865
    time(sess.time_passes(), "linking", ||
866
         link::link_binary(sess,
867
                           trans,
A
Alex Crichton 已提交
868
                           outputs,
869
                           &trans.link.crate_name));
870 871
}

872 873 874 875 876 877
fn escape_dep_filename(filename: &str) -> String {
    // Apparently clang and gcc *only* escape spaces:
    // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
    filename.replace(" ", "\\ ")
}

878
fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
879
    let mut out_filenames = Vec::new();
880
    for output_type in sess.opts.output_types.keys() {
A
Alex Crichton 已提交
881 882
        let file = outputs.path(*output_type);
        match *output_type {
883
            OutputType::Exe => {
884
                for output in sess.crate_types.borrow().iter() {
885 886
                    let p = link::filename_for_input(sess, *output, id,
                                                     outputs);
A
Alex Crichton 已提交
887 888 889 890 891 892
                    out_filenames.push(p);
                }
            }
            _ => { out_filenames.push(file); }
        }
    }
893

894 895 896 897 898
    // Write out dependency rules to the dep-info file if requested
    if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
        return
    }
    let deps_filename = outputs.path(OutputType::DepInfo);
899

A
Alex Crichton 已提交
900
    let result = (|| -> io::Result<()> {
901 902
        // Build a list of files used to compile the output and
        // write Makefile-compatible dependency rules
903
        let files: Vec<String> = sess.codemap().files.borrow()
904 905 906
                                   .iter()
                                   .filter(|fmap| fmap.is_real_file())
                                   .filter(|fmap| !fmap.is_imported())
907
                                   .map(|fmap| escape_dep_filename(&fmap.name))
908
                                   .collect();
A
Alex Crichton 已提交
909
        let mut file = try!(fs::File::create(&deps_filename));
910
        for path in &out_filenames {
911
            try!(write!(file,
912
                        "{}: {}\n\n", path.display(), files.join(" ")));
913
        }
914 915 916 917 918 919 920

        // Emit a fake target for each input file to the compilation. This
        // prevents `make` from spitting out an error if a file is later
        // deleted. For more info see #28735
        for path in files {
            try!(writeln!(file, "{}:", path));
        }
921 922 923 924 925 926
        Ok(())
    })();

    match result {
        Ok(()) => {}
        Err(e) => {
J
Jorge Aparicio 已提交
927
            sess.fatal(&format!("error writing dependencies to `{}`: {}",
928
                               deps_filename.display(), e));
929
        }
930
    }
931 932
}

N
Nick Cameron 已提交
933 934
pub fn collect_crate_types(session: &Session,
                           attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
935 936 937 938
    // 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() {
939
                Some(ref n) if *n == "rlib" => {
940 941
                    Some(config::CrateTypeRlib)
                }
942
                Some(ref n) if *n == "dylib" => {
943 944
                    Some(config::CrateTypeDylib)
                }
945
                Some(ref n) if *n == "lib" => {
946 947
                    Some(config::default_lib_output())
                }
948
                Some(ref n) if *n == "staticlib" => {
949 950
                    Some(config::CrateTypeStaticlib)
                }
951
                Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
952
                Some(_) => {
A
Aaron Turon 已提交
953
                    session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
954 955 956
                                     ast::CRATE_NODE_ID,
                                     a.span,
                                     "invalid `crate_type` \
957
                                      value".to_string());
958 959 960
                    None
                }
                _ => {
961 962
                    session.span_err(a.span, "`crate_type` requires a value");
                    session.note("for example: `#![crate_type=\"lib\"]`");
963 964 965 966 967 968 969 970
                    None
                }
            }
        } else {
            None
        }
    }).collect();

N
Nick Cameron 已提交
971 972 973 974
    // 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 已提交
975
    }
H
Haitao Li 已提交
976

N
Nick Cameron 已提交
977 978 979 980
    // 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();
981
    if base.is_empty() {
982
        base.extend(attr_types);
983
        if base.is_empty() {
984
            base.push(link::default_output_for_target(session));
985
        }
986
        base.sort();
N
Nick Cameron 已提交
987
        base.dedup();
988
    }
989

A
Aaron Turon 已提交
990
    base.into_iter().filter(|crate_type| {
991 992 993
        let res = !link::invalid_output_for_target(session, *crate_type);

        if !res {
994
            session.warn(&format!("dropping unsupported crate type `{}` \
995
                                   for target `{}`",
996
                                 *crate_type, session.opts.target_triple));
997 998 999 1000
        }

        res
    }).collect()
H
Haitao Li 已提交
1001 1002
}

1003 1004 1005 1006 1007
pub fn collect_crate_metadata(session: &Session,
                              _attrs: &[ast::Attribute]) -> Vec<String> {
    session.opts.cg.metadata.clone()
}

1008
pub fn build_output_filenames(input: &Input,
A
Alex Crichton 已提交
1009 1010
                              odir: &Option<PathBuf>,
                              ofile: &Option<PathBuf>,
1011
                              attrs: &[ast::Attribute],
E
Eduard Burtescu 已提交
1012
                              sess: &Session)
A
Alex Crichton 已提交
1013
                           -> OutputFilenames {
1014
    match *ofile {
A
Alex Crichton 已提交
1015 1016 1017 1018 1019 1020
        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(),
A
Aaron Turon 已提交
1021
                None => PathBuf::new()
A
Alex Crichton 已提交
1022 1023
            };

1024
            // If a crate name is present, we use it as the link name
1025
            let stem = sess.opts.crate_name.clone().or_else(|| {
1026
                attr::find_crate_name(attrs).map(|n| n.to_string())
1027 1028
            }).unwrap_or(input.filestem());

A
Alex Crichton 已提交
1029 1030 1031 1032
            OutputFilenames {
                out_directory: dirpath,
                out_filestem: stem,
                single_output_file: None,
1033
                extra: sess.opts.cg.extra_filename.clone(),
1034
                outputs: sess.opts.output_types.clone(),
A
Alex Crichton 已提交
1035
            }
H
Haitao Li 已提交
1036 1037
        }

A
Alex Crichton 已提交
1038
        Some(ref out_file) => {
1039 1040 1041 1042
            let unnamed_output_types = sess.opts.output_types.values()
                                           .filter(|a| a.is_none())
                                           .count();
            let ofile = if unnamed_output_types > 1 {
A
Alex Crichton 已提交
1043 1044 1045 1046 1047 1048 1049 1050 1051
                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.");
            }
1052 1053 1054

            let cur_dir = Path::new("");

A
Alex Crichton 已提交
1055
            OutputFilenames {
1056
                out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
1057
                out_filestem: out_file.file_stem().unwrap_or(OsStr::new(""))
A
Alex Crichton 已提交
1058
                                      .to_str().unwrap().to_string(),
A
Alex Crichton 已提交
1059
                single_output_file: ofile,
1060
                extra: sess.opts.cg.extra_filename.clone(),
1061
                outputs: sess.opts.output_types.clone(),
A
Alex Crichton 已提交
1062
            }
H
Haitao Li 已提交
1063
        }
1064
    }
H
Haitao Li 已提交
1065
}