driver.rs 44.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 12
use rustc::front;
use rustc::front::map as hir_map;
13
use rustc_mir as mir;
N
Niko Matsakis 已提交
14
use rustc_mir::mir_map::MirMap;
15
use rustc::session::Session;
16
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
17
use rustc::session::search_paths::PathKind;
18
use rustc::lint;
19
use rustc::middle::{stability, ty, reachable};
20 21 22
use rustc::middle::dependency_format;
use rustc::middle;
use rustc::util::common::time;
23
use rustc_borrowck as borrowck;
24
use rustc_resolve as resolve;
25 26 27
use rustc_metadata::macro_import;
use rustc_metadata::creader::LocalCrateReader;
use rustc_metadata::cstore::CStore;
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 34
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
35
use rustc_front::hir;
N
Nick Cameron 已提交
36
use rustc_front::lowering::{lower_crate, LoweringContext};
N
Nick Cameron 已提交
37
use super::Compilation;
38

39
use serialize::json;
40

41
use std::collections::HashMap;
A
Alex Crichton 已提交
42
use std::env;
43
use std::ffi::{OsString, OsStr};
A
Alex Crichton 已提交
44 45 46
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
47
use syntax::ast::{self, NodeIdAssigner};
48
use syntax::attr;
49
use syntax::attr::AttrMetaMethods;
50
use syntax::diagnostics;
51
use syntax::fold::Folder;
52
use syntax::parse;
J
John Clements 已提交
53
use syntax::parse::token;
N
Nick Cameron 已提交
54 55
use syntax::util::node_count::NodeCounter;
use syntax::visit;
56
use syntax;
57
use syntax_ext;
H
Haitao Li 已提交
58

N
Nick Cameron 已提交
59
pub fn compile_input(sess: Session,
A
Ariel Ben-Yehuda 已提交
60
                     cstore: &CStore,
N
Nick Cameron 已提交
61 62
                     cfg: ast::CrateConfig,
                     input: &Input,
A
Alex Crichton 已提交
63 64
                     outdir: &Option<PathBuf>,
                     output: &Option<PathBuf>,
65 66
                     addl_plugins: Option<Vec<String>>,
                     control: CompileController) {
67 68 69 70 71
    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 已提交
72
        if control.$point.stop == Compilation::Stop {
73 74 75 76
            return;
        }
    })}

N
Nick Cameron 已提交
77 78 79
    // 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
80
    let result = {
81
        let (outputs, expanded_crate, id) = {
N
Nick Cameron 已提交
82
            let krate = phase_1_parse_input(&sess, cfg, input);
83 84

            controller_entry_point!(after_parse,
85
                                    sess,
J
Jose Narvaez 已提交
86 87 88 89 90
                                    CompileState::state_after_parse(input, &sess, outdir, &krate));

            let outputs = build_output_filenames(input, outdir, output, &krate.attrs, &sess);
            let id = link::find_crate_name(Some(&sess), &krate.attrs, input);
            let expanded_crate = match phase_2_configure_and_expand(&sess,
A
Ariel Ben-Yehuda 已提交
91
                                                                    &cstore,
J
Jose Narvaez 已提交
92 93 94 95 96 97
                                                                    krate,
                                                                    &id[..],
                                                                    addl_plugins) {
                None => return,
                Some(k) => k,
            };
98

99
            (outputs, expanded_crate, id)
N
Nick Cameron 已提交
100
        };
101

102
        controller_entry_point!(after_expand,
103
                                sess,
104 105 106 107
                                CompileState::state_after_expand(input,
                                                                 &sess,
                                                                 outdir,
                                                                 &expanded_crate,
108
                                                                 &id[..]));
109

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

        // Discard MTWT tables that aren't required past lowering to HIR.
        if !sess.opts.debugging_opts.keep_mtwt_tables &&
           !sess.opts.debugging_opts.save_analysis {
            syntax::ext::mtwt::clear_tables();
        }

123
        let arenas = ty::CtxtArenas::new();
124
        let ast_map = make_map(&sess, &mut hir_forest);
125

126
        write_out_deps(&sess, &outputs, &id);
N
Nick Cameron 已提交
127

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

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

J
Jose Narvaez 已提交
143 144 145
        time(sess.time_passes(),
             "early lint checks",
             || lint::check_ast_crate(&sess, &expanded_crate));
146

147
        phase_3_run_analysis_passes(&sess,
A
Ariel Ben-Yehuda 已提交
148
                                    &cstore,
149 150
                                    ast_map,
                                    &arenas,
151
                                    &id,
152
                                    control.make_glob_map,
N
Niko Matsakis 已提交
153
                                    |tcx, mir_map, analysis| {
154

J
Jose Narvaez 已提交
155 156 157 158 159 160 161 162
                                        {
                                            let state =
                                                CompileState::state_after_analysis(input,
                                                                                   &tcx.sess,
                                                                                   outdir,
                                                                                   &expanded_crate,
                                                                                   tcx.map.krate(),
                                                                                   &analysis,
163
                                                                                   &mir_map,
J
Jose Narvaez 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                                                                                   tcx,
                                                                                   &lcx,
                                                                                   &id);
                                            (control.after_analysis.callback)(state);

                                            tcx.sess.abort_if_errors();
                                            if control.after_analysis.stop == Compilation::Stop {
                                                return Err(());
                                            }
                                        }

                                        if log_enabled!(::log::INFO) {
                                            println!("Pre-trans");
                                            tcx.print_debug_stats();
                                        }
                                        let trans = phase_4_translate_to_llvm(tcx,
180
                                                                              mir_map,
J
Jose Narvaez 已提交
181 182 183 184 185 186 187 188 189 190 191 192
                                                                              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();

                                        Ok((outputs, trans))
                                    })
193
    };
N
Nick Cameron 已提交
194

195 196 197 198
    let (outputs, trans) = if let Ok(out) = result {
        out
    } else {
        return;
N
Nick Cameron 已提交
199
    };
200

N
Nick Cameron 已提交
201
    phase_5_run_llvm_passes(&sess, &trans, &outputs);
202 203

    controller_entry_point!(after_llvm,
204
                            sess,
J
Jose Narvaez 已提交
205
                            CompileState::state_after_llvm(input, &sess, outdir, &trans));
206

N
Nick Cameron 已提交
207
    phase_6_link_output(&sess, &trans, &outputs);
208
}
H
Haitao Li 已提交
209

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

216
pub fn source_name(input: &Input) -> String {
217
    match *input {
E
Eduard Burtescu 已提交
218
        // FIXME (#9639): This needs to handle non-utf8 paths
A
Alex Crichton 已提交
219
        Input::File(ref ifile) => ifile.to_str().unwrap().to_string(),
J
Jose Narvaez 已提交
220
        Input::Str(_) => anon_src(),
221 222 223
    }
}

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

pub struct PhaseController<'a> {
N
Nick Cameron 已提交
262
    pub stop: Compilation,
263 264 265 266 267 268
    pub callback: Box<Fn(CompileState) -> () + 'a>,
}

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

/// 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>,
287 288
    pub hir_crate: Option<&'a hir::Crate>,
    pub ast_map: Option<&'a hir_map::Map<'ast>>,
289
    pub mir_map: Option<&'a MirMap<'tcx>>,
290
    pub analysis: Option<&'a ty::CrateAnalysis<'a>>,
291
    pub tcx: Option<&'a ty::ctxt<'tcx>>,
N
Nick Cameron 已提交
292
    pub lcx: Option<&'a LoweringContext<'a>>,
293 294 295 296 297 298
    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 已提交
299
             out_dir: &'a Option<PathBuf>)
300 301 302 303
             -> CompileState<'a, 'ast, 'tcx> {
        CompileState {
            input: input,
            session: session,
A
Alex Crichton 已提交
304
            out_dir: out_dir.as_ref().map(|s| &**s),
305 306 307 308 309
            cfg: None,
            krate: None,
            crate_name: None,
            output_filenames: None,
            expanded_crate: None,
310
            hir_crate: None,
311 312
            ast_map: None,
            analysis: None,
313
            mir_map: None,
314
            tcx: None,
N
Nick Cameron 已提交
315
            lcx: None,
316 317 318 319 320 321
            trans: None,
        }
    }

    fn state_after_parse(input: &'a Input,
                         session: &'a Session,
A
Alex Crichton 已提交
322
                         out_dir: &'a Option<PathBuf>,
323 324
                         krate: &'a ast::Crate)
                         -> CompileState<'a, 'ast, 'tcx> {
J
Jose Narvaez 已提交
325
        CompileState { krate: Some(krate), ..CompileState::empty(input, session, out_dir) }
326 327 328 329
    }

    fn state_after_expand(input: &'a Input,
                          session: &'a Session,
A
Alex Crichton 已提交
330
                          out_dir: &'a Option<PathBuf>,
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),
J
Jose Narvaez 已提交
337
            ..CompileState::empty(input, session, out_dir)
338 339 340
        }
    }

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

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


    fn state_after_llvm(input: &'a Input,
                        session: &'a Session,
A
Alex Crichton 已提交
386
                        out_dir: &'a Option<PathBuf>,
387 388
                        trans: &'a trans::CrateTranslation)
                        -> CompileState<'a, 'ast, 'tcx> {
J
Jose Narvaez 已提交
389
        CompileState { trans: Some(trans), ..CompileState::empty(input, session, out_dir) }
390 391 392
    }
}

J
Jose Narvaez 已提交
393
pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) -> ast::Crate {
M
Murarth 已提交
394 395 396 397 398 399
    // 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();

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

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

N
Nick Cameron 已提交
418 419 420 421 422
    if sess.opts.debugging_opts.input_stats {
        println!("Lines of code:             {}", sess.codemap().count_lines());
        println!("Pre-expansion node count:  {}", count_nodes(&krate));
    }

S
Seo Sanghyeon 已提交
423
    if let Some(ref s) = sess.opts.show_span {
424
        syntax::show_span::run(sess.diagnostic(), s, &krate);
425 426
    }

427
    krate
428
}
H
Haitao Li 已提交
429

N
Nick Cameron 已提交
430 431 432 433 434 435
fn count_nodes(krate: &ast::Crate) -> usize {
    let mut counter = NodeCounter::new();
    visit::walk_crate(&mut counter, krate);
    counter.count
}

436 437
// For continuing compilation after a parsed crate has been
// modified
438

439
/// Run the "early phases" of the compiler: initial `cfg` processing,
B
Brian Anderson 已提交
440
/// loading compiler plugins (including those from `addl_plugins`),
441 442 443
/// 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.
444 445
///
/// Returns `None` if we're aborting after handling -W help.
E
Eduard Burtescu 已提交
446
pub fn phase_2_configure_and_expand(sess: &Session,
A
Ariel Ben-Yehuda 已提交
447
                                    cstore: &CStore,
448
                                    mut krate: ast::Crate,
449
                                    crate_name: &str,
450
                                    addl_plugins: Option<Vec<String>>)
451
                                    -> Option<ast::Crate> {
452
    let time_passes = sess.time_passes();
H
Haitao Li 已提交
453

454 455
    // strip before anything else because crate metadata may use #[cfg_attr]
    // and so macros can depend on configuration variables, such as
456
    //
457
    //   #[macro_use] #[cfg(foo)]
458 459 460
    //   mod bar { macro_rules! baz!(() => {{}}) }
    //
    // baz! should not use this definition unless foo is enabled.
461

462
    let mut feature_gated_cfgs = vec![];
J
Jose Narvaez 已提交
463 464 465
    krate = time(time_passes, "configuration 1", || {
        syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs)
    });
466

J
Jose Narvaez 已提交
467 468
    *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
    *sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs);
469

470
    time(time_passes, "recursion limit", || {
471 472 473
        middle::recursion_limit::update_recursion_limit(sess, &krate);
    });

474
    time(time_passes, "gated macro checking", || {
J
Jose Narvaez 已提交
475 476 477
        let features = syntax::feature_gate::check_crate_macros(sess.codemap(),
                                                                &sess.parse_sess.span_diagnostic,
                                                                &krate);
C
Corey Richardson 已提交
478 479 480 481 482 483

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

484

J
Jose Narvaez 已提交
485 486 487
    krate = time(time_passes, "crate injection", || {
        syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone())
    });
488

J
Jose Narvaez 已提交
489 490
    let macros = time(time_passes,
                      "macro loading",
491
                      || macro_import::read_macro_defs(sess, &cstore, &krate));
492

493
    let mut addl_plugins = Some(addl_plugins);
J
Jose Narvaez 已提交
494
    let registrars = time(time_passes, "plugin loading", || {
A
Ariel Ben-Yehuda 已提交
495
        plugin::load::load_plugins(sess, &cstore, &krate, addl_plugins.take().unwrap())
J
Jose Narvaez 已提交
496
    });
497

498
    let mut registry = Registry::new(sess, &krate);
499

500
    time(time_passes, "plugin registration", || {
N
Nick Cameron 已提交
501
        if sess.features.borrow().rustc_diagnostic_macros {
502
            registry.register_macro("__diagnostic_used",
J
Jose Narvaez 已提交
503
                                    diagnostics::plugin::expand_diagnostic_used);
504
            registry.register_macro("__register_diagnostic",
J
Jose Narvaez 已提交
505
                                    diagnostics::plugin::expand_register_diagnostic);
506
            registry.register_macro("__build_diagnostic_array",
J
Jose Narvaez 已提交
507
                                    diagnostics::plugin::expand_build_diagnostic_array);
508 509
        }

510
        for registrar in registrars {
511 512
            registry.args_hidden = Some(registrar.args);
            (registrar.fun)(&mut registry);
513
        }
514
    });
515

N
Nick Cameron 已提交
516
    let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
517
                   llvm_passes, attributes, .. } = registry;
518

K
Keegan McAllister 已提交
519 520
    {
        let mut ls = sess.lint_store.borrow_mut();
N
Nick Cameron 已提交
521 522 523 524 525
        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 已提交
526
        }
527

528
        for (name, to) in lint_groups {
529 530
            ls.register_group(Some(sess), true, name, to);
        }
531 532

        *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
533
        *sess.plugin_attributes.borrow_mut() = attributes.clone();
K
Keegan McAllister 已提交
534 535 536
    }

    // Lint plugins are registered; now we can process command line flags.
537
    if sess.opts.describe_lints {
K
Keegan McAllister 已提交
538
        super::describe_lints(&*sess.lint_store.borrow(), true);
539 540 541 542 543 544 545
        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();

546 547 548 549 550 551 552 553 554 555 556 557 558
    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());
559
        }
560 561 562 563 564 565 566
        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,
        };
567 568 569 570 571 572 573 574 575
        let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,
                                                      krate.config.clone(),
                                                      cfg,
                                                      &mut feature_gated_cfgs);
        syntax_ext::register_builtins(&mut ecx.syntax_env);
        let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
                                                                   macros,
                                                                   syntax_exts,
                                                                   krate);
576 577 578
        if cfg!(windows) {
            env::set_var("PATH", &_old_path);
        }
579
        *sess.available_macros.borrow_mut() = macro_names;
580 581
        ret
    });
582

583 584 585 586
    // 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)
587
    time(time_passes, "complete gated feature checking 1", || {
J
Jose Narvaez 已提交
588 589 590 591 592
        let features = syntax::feature_gate::check_crate(sess.codemap(),
                                                         &sess.parse_sess.span_diagnostic,
                                                         &krate,
                                                         &attributes,
                                                         sess.opts.unstable_features);
593
        *sess.features.borrow_mut() = features;
C
Corey Richardson 已提交
594 595 596
        sess.abort_if_errors();
    });

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

599
    // strip again, in case expansion added anything with a #[cfg].
J
Jose Narvaez 已提交
600 601 602
    krate = time(time_passes, "configuration 2", || {
        syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs)
    });
603 604 605 606 607 608

    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 {
609
            cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
610 611
        }
    });
612

J
Jose Narvaez 已提交
613 614 615
    krate = time(time_passes, "maybe building test harness", || {
        syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic())
    });
616

J
Jose Narvaez 已提交
617 618 619
    krate = time(time_passes,
                 "prelude injection",
                 || syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate));
B
Brian Anderson 已提交
620

J
Jose Narvaez 已提交
621 622 623
    time(time_passes,
         "checking that all macro invocations are gone",
         || syntax::ext::expand::check_for_macros(&sess.parse_sess, &krate));
624

J
Jose Narvaez 已提交
625 626 627
    time(time_passes,
         "checking for inline asm in case the target doesn't support it",
         || middle::check_no_asm::check_crate(sess, &krate));
628

629 630 631
    // 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`)
632
    time(time_passes, "complete gated feature checking 2", || {
J
Jose Narvaez 已提交
633 634 635 636 637
        let features = syntax::feature_gate::check_crate(sess.codemap(),
                                                         &sess.parse_sess.span_diagnostic,
                                                         &krate,
                                                         &attributes,
                                                         sess.opts.unstable_features);
638 639 640 641
        *sess.features.borrow_mut() = features;
        sess.abort_if_errors();
    });

N
Nick Cameron 已提交
642 643 644 645
    if sess.opts.debugging_opts.input_stats {
        println!("Post-expansion node count: {}", count_nodes(&krate));
    }

646 647 648
    Some(krate)
}

J
Jose Narvaez 已提交
649
pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
650
    struct NodeIdAssigner<'a> {
J
Jose Narvaez 已提交
651
        sess: &'a Session,
652 653
    }

654 655
    impl<'a> Folder for NodeIdAssigner<'a> {
        fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
656 657 658 659 660
            assert_eq!(old_id, ast::DUMMY_NODE_ID);
            self.sess.next_node_id()
        }
    }

661 662 663
    let krate = time(sess.time_passes(),
                     "assigning node ids",
                     || NodeIdAssigner { sess: sess }.fold_crate(krate));
664

665
    if sess.opts.debugging_opts.ast_json {
666
        println!("{}", json::as_json(&krate));
667 668
    }

669 670 671 672 673 674 675 676 677 678 679
    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));

680
    map
681
}
682

683 684 685
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
686
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
A
Ariel Ben-Yehuda 已提交
687
                                               cstore: &CStore,
688
                                               ast_map: front::map::Map<'tcx>,
689
                                               arenas: &'tcx ty::CtxtArenas<'tcx>,
690
                                               name: &str,
691 692
                                               make_glob_map: resolve::MakeGlobMap,
                                               f: F)
693
                                               -> R
J
Jose Narvaez 已提交
694
    where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R
695
{
696
    let time_passes = sess.time_passes();
697
    let krate = ast_map.krate();
698

J
Jose Narvaez 已提交
699 700
    time(time_passes,
         "external crate/lib resolution",
A
Ariel Ben-Yehuda 已提交
701
         || LocalCrateReader::new(sess, cstore, &ast_map).read_crates(krate));
B
Brian Anderson 已提交
702

J
Jose Narvaez 已提交
703 704 705
    let lang_items = time(time_passes,
                          "language item collection",
                          || middle::lang_items::collect_language_items(&sess, &ast_map));
706

N
Nick Cameron 已提交
707
    let resolve::CrateMap {
708 709
        def_map,
        freevars,
710
        export_map,
711 712
        trait_map,
        external_exports,
713
        glob_map,
J
Jose Narvaez 已提交
714 715
    } = time(time_passes,
             "resolution",
716
             || resolve::resolve_crate(sess, &ast_map, make_glob_map));
B
Brian Anderson 已提交
717

J
Jose Narvaez 已提交
718 719 720
    let named_region_map = time(time_passes,
                                "lifetime resolution",
                                || middle::resolve_lifetime::krate(sess, krate, &def_map.borrow()));
721

J
Jose Narvaez 已提交
722 723
    time(time_passes,
         "looking for entry point",
724
         || middle::entry::find_entry_point(sess, &ast_map));
B
Brian Anderson 已提交
725

J
Jose Narvaez 已提交
726 727 728
    sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || {
        plugin::build::find_plugin_registrar(sess.diagnostic(), krate)
    }));
729

J
Jose Narvaez 已提交
730 731 732
    let region_map = time(time_passes,
                          "region resolution",
                          || middle::region::resolve_crate(sess, krate));
733

J
Jose Narvaez 已提交
734 735 736
    time(time_passes,
         "loop checking",
         || middle::check_loop::check_crate(sess, krate));
737

J
Jose Narvaez 已提交
738 739 740
    time(time_passes,
         "static item recursion checking",
         || middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &ast_map));
741

742 743 744 745 746 747 748 749 750 751
    ty::ctxt::create_and_enter(sess,
                               arenas,
                               def_map,
                               named_region_map,
                               ast_map,
                               freevars,
                               region_map,
                               lang_items,
                               stability::Index::new(krate),
                               |tcx| {
J
Jose Narvaez 已提交
752 753 754 755 756 757 758
                                   // passes are timed inside typeck
                                   typeck::check_crate(tcx, trait_map);

                                   time(time_passes,
                                        "const checking",
                                        || middle::check_const::check_crate(tcx));

759
                                   let access_levels =
J
Jose Narvaez 已提交
760 761 762 763 764 765 766 767
                                       time(time_passes, "privacy checking", || {
                                           rustc_privacy::check_crate(tcx,
                                                                      &export_map,
                                                                      external_exports)
                                       });

                                   // Do not move this check past lint
                                   time(time_passes, "stability index", || {
768
                                       tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
J
Jose Narvaez 已提交
769 770 771 772 773 774 775 776 777 778 779 780 781 782
                                   });

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

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

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

783 784 785 786
                                   let mir_map =
                                       time(time_passes,
                                            "MIR dump",
                                            || mir::mir_map::build_mir_for_crate(tcx));
J
Jose Narvaez 已提交
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810

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

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

                                   time(time_passes,
                                        "rvalue checking",
                                        || 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 =
                                       time(time_passes,
                                            "reachability checking",
811
                                            || reachable::find_reachable(tcx, &access_levels));
J
Jose Narvaez 已提交
812 813

                                   time(time_passes, "death checking", || {
814
                                       middle::dead::check_crate(tcx, &access_levels);
J
Jose Narvaez 已提交
815 816 817 818 819 820 821 822 823 824 825 826 827 828
                                   });

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

                                   time(time_passes, "unused lib feature checking", || {
                                       stability::check_unused_or_stable_features(&tcx.sess,
                                                                                  lib_features_used)
                                   });

                                   time(time_passes,
                                        "lint checking",
829
                                        || lint::check_crate(tcx, &access_levels));
J
Jose Narvaez 已提交
830 831 832 833 834 835 836 837

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

                                   f(tcx,
                                     mir_map,
                                     ty::CrateAnalysis {
                                         export_map: export_map,
838
                                         access_levels: access_levels,
J
Jose Narvaez 已提交
839 840 841 842 843
                                         reachable: reachable_map,
                                         name: name,
                                         glob_map: glob_map,
                                     })
                               })
844
}
J
James Miller 已提交
845

846 847
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
N
Niko Matsakis 已提交
848
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
849
                                       mut mir_map: MirMap<'tcx>,
N
Niko Matsakis 已提交
850 851
                                       analysis: ty::CrateAnalysis)
                                       -> trans::CrateTranslation {
852
    let time_passes = tcx.sess.time_passes();
853

J
Jose Narvaez 已提交
854 855 856
    time(time_passes,
         "resolving dependency formats",
         || dependency_format::calculate(&tcx.sess));
857

858 859 860 861
    time(time_passes,
         "erasing regions from MIR",
         || mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));

862
    // Option dance to work around the lack of stack once closures.
J
Jose Narvaez 已提交
863 864
    time(time_passes,
         "translation",
865
         move || trans::trans_crate(tcx, &mir_map, analysis))
866 867 868 869
}

/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
E
Eduard Burtescu 已提交
870
pub fn phase_5_run_llvm_passes(sess: &Session,
871
                               trans: &trans::CrateTranslation,
872
                               outputs: &OutputFilenames) {
873
    if sess.opts.cg.no_integrated_as {
874 875
        let mut map = HashMap::new();
        map.insert(OutputType::Assembly, None);
J
Jose Narvaez 已提交
876 877 878
        time(sess.time_passes(),
             "LLVM passes",
             || write::run_passes(sess, trans, &map, outputs));
879

880
        write::run_assembler(sess, outputs);
V
Vadim Chugunov 已提交
881

882
        // Remove assembly source, unless --save-temps was specified
883
        if !sess.opts.cg.save_temps {
884
            fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap();
V
Vadim Chugunov 已提交
885
        }
886
    } else {
J
Jose Narvaez 已提交
887 888 889
        time(sess.time_passes(),
             "LLVM passes",
             || write::run_passes(sess, trans, &sess.opts.output_types, outputs));
890
    }
891 892

    sess.abort_if_errors();
893
}
H
Haitao Li 已提交
894

895 896
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
E
Eduard Burtescu 已提交
897
pub fn phase_6_link_output(sess: &Session,
898
                           trans: &trans::CrateTranslation,
899
                           outputs: &OutputFilenames) {
J
Jose Narvaez 已提交
900 901 902
    time(sess.time_passes(),
         "linking",
         || link::link_binary(sess, trans, outputs, &trans.link.crate_name));
903 904
}

905 906 907
fn escape_dep_filename(filename: &str) -> String {
    // Apparently clang and gcc *only* escape spaces:
    // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
J
Jose Narvaez 已提交
908
    filename.replace(" ", "\\ ")
909 910
}

911
fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
912
    let mut out_filenames = Vec::new();
913
    for output_type in sess.opts.output_types.keys() {
A
Alex Crichton 已提交
914 915
        let file = outputs.path(*output_type);
        match *output_type {
916
            OutputType::Exe => {
917
                for output in sess.crate_types.borrow().iter() {
J
Jose Narvaez 已提交
918
                    let p = link::filename_for_input(sess, *output, id, outputs);
A
Alex Crichton 已提交
919 920 921
                    out_filenames.push(p);
                }
            }
J
Jose Narvaez 已提交
922 923 924
            _ => {
                out_filenames.push(file);
            }
A
Alex Crichton 已提交
925 926
        }
    }
927

928 929
    // Write out dependency rules to the dep-info file if requested
    if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
J
Jose Narvaez 已提交
930
        return;
931 932
    }
    let deps_filename = outputs.path(OutputType::DepInfo);
933

J
Jose Narvaez 已提交
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
    let result =
        (|| -> io::Result<()> {
            // Build a list of files used to compile the output and
            // write Makefile-compatible dependency rules
            let files: Vec<String> = sess.codemap()
                                         .files
                                         .borrow()
                                         .iter()
                                         .filter(|fmap| fmap.is_real_file())
                                         .filter(|fmap| !fmap.is_imported())
                                         .map(|fmap| escape_dep_filename(&fmap.name))
                                         .collect();
            let mut file = try!(fs::File::create(&deps_filename));
            for path in &out_filenames {
                try!(write!(file, "{}: {}\n\n", path.display(), files.join(" ")));
            }
950

J
Jose Narvaez 已提交
951 952 953 954 955 956 957 958
            // 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));
            }
            Ok(())
        })();
959 960 961 962

    match result {
        Ok(()) => {}
        Err(e) => {
J
Jorge Aparicio 已提交
963
            sess.fatal(&format!("error writing dependencies to `{}`: {}",
J
Jose Narvaez 已提交
964 965
                                deps_filename.display(),
                                e));
966
        }
967
    }
968 969
}

J
Jose Narvaez 已提交
970
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
971
    // Unconditionally collect crate types from attributes to make them used
J
Jose Narvaez 已提交
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    let attr_types: Vec<config::CrateType> =
        attrs.iter()
             .filter_map(|a| {
                 if a.check_name("crate_type") {
                     match a.value_str() {
                         Some(ref n) if *n == "rlib" => {
                             Some(config::CrateTypeRlib)
                         }
                         Some(ref n) if *n == "dylib" => {
                             Some(config::CrateTypeDylib)
                         }
                         Some(ref n) if *n == "lib" => {
                             Some(config::default_lib_output())
                         }
                         Some(ref n) if *n == "staticlib" => {
                             Some(config::CrateTypeStaticlib)
                         }
                         Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
                         Some(_) => {
                             session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
                                              ast::CRATE_NODE_ID,
                                              a.span,
                                              "invalid `crate_type` value".to_string());
                             None
                         }
                         _ => {
                             session.span_err(a.span, "`crate_type` requires a value");
                             session.note("for example: `#![crate_type=\"lib\"]`");
                             None
                         }
                     }
                 } else {
                     None
                 }
             })
             .collect();
1008

N
Nick Cameron 已提交
1009 1010 1011
    // If we're generating a test executable, then ignore all other output
    // styles at all other locations
    if session.opts.test {
J
Jose Narvaez 已提交
1012
        return vec![config::CrateTypeExecutable];
S
Steven Stewart-Gallus 已提交
1013
    }
H
Haitao Li 已提交
1014

N
Nick Cameron 已提交
1015 1016 1017 1018
    // 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();
1019
    if base.is_empty() {
1020
        base.extend(attr_types);
1021
        if base.is_empty() {
1022
            base.push(link::default_output_for_target(session));
1023
        }
1024
        base.sort();
N
Nick Cameron 已提交
1025
        base.dedup();
1026
    }
1027

J
Jose Narvaez 已提交
1028 1029 1030
    base.into_iter()
        .filter(|crate_type| {
            let res = !link::invalid_output_for_target(session, *crate_type);
1031

J
Jose Narvaez 已提交
1032 1033 1034 1035 1036
            if !res {
                session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",
                                      *crate_type,
                                      session.opts.target_triple));
            }
1037

J
Jose Narvaez 已提交
1038 1039 1040
            res
        })
        .collect()
H
Haitao Li 已提交
1041 1042
}

J
Jose Narvaez 已提交
1043
pub fn collect_crate_metadata(session: &Session, _attrs: &[ast::Attribute]) -> Vec<String> {
1044 1045 1046
    session.opts.cg.metadata.clone()
}

1047
pub fn build_output_filenames(input: &Input,
A
Alex Crichton 已提交
1048 1049
                              odir: &Option<PathBuf>,
                              ofile: &Option<PathBuf>,
1050
                              attrs: &[ast::Attribute],
E
Eduard Burtescu 已提交
1051
                              sess: &Session)
J
Jose Narvaez 已提交
1052
                              -> OutputFilenames {
1053
    match *ofile {
A
Alex Crichton 已提交
1054 1055 1056 1057 1058 1059
        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(),
J
Jose Narvaez 已提交
1060
                None => PathBuf::new(),
A
Alex Crichton 已提交
1061 1062
            };

1063
            // If a crate name is present, we use it as the link name
J
Jose Narvaez 已提交
1064 1065 1066 1067 1068
            let stem = sess.opts
                           .crate_name
                           .clone()
                           .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
                           .unwrap_or(input.filestem());
1069

A
Alex Crichton 已提交
1070 1071 1072 1073
            OutputFilenames {
                out_directory: dirpath,
                out_filestem: stem,
                single_output_file: None,
1074
                extra: sess.opts.cg.extra_filename.clone(),
1075
                outputs: sess.opts.output_types.clone(),
A
Alex Crichton 已提交
1076
            }
H
Haitao Li 已提交
1077 1078
        }

A
Alex Crichton 已提交
1079
        Some(ref out_file) => {
J
Jose Narvaez 已提交
1080 1081 1082
            let unnamed_output_types = sess.opts
                                           .output_types
                                           .values()
1083 1084 1085
                                           .filter(|a| a.is_none())
                                           .count();
            let ofile = if unnamed_output_types > 1 {
J
Jose Narvaez 已提交
1086 1087
                sess.warn("ignoring specified output filename because multiple outputs were \
                           requested");
A
Alex Crichton 已提交
1088 1089 1090 1091 1092 1093 1094
                None
            } else {
                Some(out_file.clone())
            };
            if *odir != None {
                sess.warn("ignoring --out-dir flag due to -o flag.");
            }
1095 1096 1097

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

A
Alex Crichton 已提交
1098
            OutputFilenames {
1099
                out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
J
Jose Narvaez 已提交
1100 1101 1102 1103 1104
                out_filestem: out_file.file_stem()
                                      .unwrap_or(OsStr::new(""))
                                      .to_str()
                                      .unwrap()
                                      .to_string(),
A
Alex Crichton 已提交
1105
                single_output_file: ofile,
1106
                extra: sess.opts.cg.extra_filename.clone(),
1107
                outputs: sess.opts.output_types.clone(),
A
Alex Crichton 已提交
1108
            }
H
Haitao Li 已提交
1109
        }
1110
    }
H
Haitao Li 已提交
1111
}