1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc
::dep_graph
::DepGraph
;
13 use rustc
::hir
::map
as hir_map
;
15 use rustc
::mir
::mir_map
::MirMap
;
16 use rustc
::session
::{Session, CompileResult, compile_result_from_err_count}
;
17 use rustc
::session
::config
::{self, Input, OutputFilenames, OutputType}
;
18 use rustc
::session
::search_paths
::PathKind
;
20 use rustc
::middle
::{self, dependency_format, stability, reachable}
;
21 use rustc
::middle
::privacy
::AccessLevels
;
22 use rustc
::ty
::{self, TyCtxt}
;
23 use rustc
::util
::common
::time
;
24 use rustc
::util
::nodemap
::NodeSet
;
25 use rustc_back
::sha2
::{Sha256, Digest}
;
26 use rustc_borrowck
as borrowck
;
27 use rustc_incremental
;
28 use rustc_resolve
as resolve
;
29 use rustc_metadata
::macro_import
;
30 use rustc_metadata
::creader
::LocalCrateReader
;
31 use rustc_metadata
::cstore
::CStore
;
32 use rustc_trans
::back
::link
;
33 use rustc_trans
::back
::write
;
34 use rustc_trans
as trans
;
35 use rustc_typeck
as typeck
;
37 use rustc_plugin
::registry
::Registry
;
38 use rustc_plugin
as plugin
;
39 use rustc
::hir
::lowering
::{lower_crate, LoweringContext}
;
40 use rustc_passes
::{no_asm, loops, consts, const_fn, rvalues, static_recursion}
;
41 use rustc_const_eval
::check_match
;
42 use super::Compilation
;
46 use std
::collections
::HashMap
;
48 use std
::ffi
::{OsString, OsStr}
;
50 use std
::io
::{self, Write}
;
51 use std
::path
::{Path, PathBuf}
;
52 use syntax
::ast
::{self, NodeIdAssigner}
;
53 use syntax
::attr
::{self, AttrMetaMethods}
;
54 use syntax
::diagnostics
;
55 use syntax
::fold
::Folder
;
56 use syntax
::parse
::{self, PResult, token}
;
57 use syntax
::util
::node_count
::NodeCounter
;
62 pub fn compile_input(sess
: &Session
,
64 cfg
: ast
::CrateConfig
,
66 outdir
: &Option
<PathBuf
>,
67 output
: &Option
<PathBuf
>,
68 addl_plugins
: Option
<Vec
<String
>>,
69 control
: &CompileController
) -> CompileResult
{
70 macro_rules
! controller_entry_point
{
71 ($point
: ident
, $tsess
: expr
, $make_state
: expr
, $phase_result
: expr
) => {{
72 let state
= $make_state
;
73 let phase_result
: &CompileResult
= &$phase_result
;
74 if phase_result
.is_ok() || control
.$point
.run_callback_on_error
{
75 (control
.$point
.callback
)(state
);
78 if control
.$point
.stop
== Compilation
::Stop
{
79 return compile_result_from_err_count($tsess
.err_count());
84 // We need nested scopes here, because the intermediate results can keep
85 // large chunks of memory alive and we want to free them as soon as
86 // possible to keep the peak memory usage low
87 let (outputs
, trans
) = {
88 let (outputs
, expanded_crate
, id
) = {
89 let krate
= match phase_1_parse_input(sess
, cfg
, input
) {
91 Err(mut parse_error
) => {
97 controller_entry_point
!(after_parse
,
99 CompileState
::state_after_parse(input
, sess
, outdir
, &krate
),
102 let outputs
= build_output_filenames(input
, outdir
, output
, &krate
.attrs
, sess
);
103 let id
= link
::find_crate_name(Some(sess
), &krate
.attrs
, input
);
104 let expanded_crate
= phase_2_configure_and_expand(sess
,
110 (outputs
, expanded_crate
, id
)
113 controller_entry_point
!(after_expand
,
115 CompileState
::state_after_expand(input
,
122 let expanded_crate
= assign_node_ids(sess
, expanded_crate
);
124 let lcx
= LoweringContext
::new(sess
, Some(&expanded_crate
));
125 let dep_graph
= DepGraph
::new(sess
.opts
.build_dep_graph());
126 let mut hir_forest
= time(sess
.time_passes(),
127 "lowering ast -> hir",
128 || hir_map
::Forest
::new(lower_crate(&lcx
, &expanded_crate
),
131 // Discard MTWT tables that aren't required past lowering to HIR.
132 if !sess
.opts
.debugging_opts
.keep_mtwt_tables
&&
133 !sess
.opts
.debugging_opts
.save_analysis
{
134 syntax
::ext
::mtwt
::clear_tables();
137 let arenas
= ty
::CtxtArenas
::new();
138 let hir_map
= make_map(sess
, &mut hir_forest
);
140 write_out_deps(sess
, &outputs
, &id
);
143 let _ignore
= hir_map
.dep_graph
.in_ignore();
144 controller_entry_point
!(after_write_deps
,
146 CompileState
::state_after_write_deps(input
,
157 time(sess
.time_passes(), "attribute checking", || {
158 hir
::check_attr
::check_crate(sess
, &expanded_crate
);
161 time(sess
.time_passes(),
163 || lint
::check_ast_crate(sess
, &expanded_crate
));
165 let opt_crate
= if sess
.opts
.debugging_opts
.keep_ast
||
166 sess
.opts
.debugging_opts
.save_analysis
{
167 Some(&expanded_crate
)
169 drop(expanded_crate
);
173 phase_3_run_analysis_passes(sess
,
178 control
.make_glob_map
,
179 |tcx
, mir_map
, analysis
, result
| {
181 // Eventually, we will want to track plugins.
182 let _ignore
= tcx
.dep_graph
.in_ignore();
184 let state
= CompileState
::state_after_analysis(input
,
194 (control
.after_analysis
.callback
)(state
);
196 if control
.after_analysis
.stop
== Compilation
::Stop
{
203 if log_enabled
!(::log
::INFO
) {
204 println
!("Pre-trans");
205 tcx
.print_debug_stats();
207 let trans
= phase_4_translate_to_llvm(tcx
,
211 if log_enabled
!(::log
::INFO
) {
212 println
!("Post-trans");
213 tcx
.print_debug_stats();
216 // Discard interned strings as they are no longer required.
217 token
::get_ident_interner().clear();
223 let phase5_result
= phase_5_run_llvm_passes(sess
, &trans
, &outputs
);
225 controller_entry_point
!(after_llvm
,
227 CompileState
::state_after_llvm(input
, sess
, outdir
, &trans
),
231 phase_6_link_output(sess
, &trans
, &outputs
);
236 /// The name used for source code that doesn't originate in a file
237 /// (e.g. source from stdin or a string)
238 pub fn anon_src() -> String
{
242 pub fn source_name(input
: &Input
) -> String
{
244 // FIXME (#9639): This needs to handle non-utf8 paths
245 Input
::File(ref ifile
) => ifile
.to_str().unwrap().to_string(),
246 Input
::Str { ref name, .. }
=> name
.clone(),
250 /// CompileController is used to customise compilation, it allows compilation to
251 /// be stopped and/or to call arbitrary code at various points in compilation.
252 /// It also allows for various flags to be set to influence what information gets
253 /// collected during compilation.
255 /// This is a somewhat higher level controller than a Session - the Session
256 /// controls what happens in each phase, whereas the CompileController controls
257 /// whether a phase is run at all and whether other code (from outside the
258 /// the compiler) is run between phases.
260 /// Note that if compilation is set to stop and a callback is provided for a
261 /// given entry point, the callback is called before compilation is stopped.
263 /// Expect more entry points to be added in the future.
264 pub struct CompileController
<'a
> {
265 pub after_parse
: PhaseController
<'a
>,
266 pub after_expand
: PhaseController
<'a
>,
267 pub after_write_deps
: PhaseController
<'a
>,
268 pub after_analysis
: PhaseController
<'a
>,
269 pub after_llvm
: PhaseController
<'a
>,
271 pub make_glob_map
: resolve
::MakeGlobMap
,
274 impl<'a
> CompileController
<'a
> {
275 pub fn basic() -> CompileController
<'a
> {
277 after_parse
: PhaseController
::basic(),
278 after_expand
: PhaseController
::basic(),
279 after_write_deps
: PhaseController
::basic(),
280 after_analysis
: PhaseController
::basic(),
281 after_llvm
: PhaseController
::basic(),
282 make_glob_map
: resolve
::MakeGlobMap
::No
,
287 pub struct PhaseController
<'a
> {
288 pub stop
: Compilation
,
289 // If true then the compiler will try to run the callback even if the phase
290 // ends with an error. Note that this is not always possible.
291 pub run_callback_on_error
: bool
,
292 pub callback
: Box
<Fn(CompileState
) -> () + 'a
>,
295 impl<'a
> PhaseController
<'a
> {
296 pub fn basic() -> PhaseController
<'a
> {
298 stop
: Compilation
::Continue
,
299 run_callback_on_error
: false,
300 callback
: box |_
| {}
,
305 /// State that is passed to a callback. What state is available depends on when
306 /// during compilation the callback is made. See the various constructor methods
307 /// (`state_*`) in the impl to see which data is provided for any given entry point.
308 pub struct CompileState
<'a
, 'ast
: 'a
, 'tcx
: 'a
> {
309 pub input
: &'a Input
,
310 pub session
: &'a Session
,
311 pub cfg
: Option
<&'a ast
::CrateConfig
>,
312 pub krate
: Option
<&'a ast
::Crate
>,
313 pub crate_name
: Option
<&'a
str>,
314 pub output_filenames
: Option
<&'a OutputFilenames
>,
315 pub out_dir
: Option
<&'a Path
>,
316 pub expanded_crate
: Option
<&'a ast
::Crate
>,
317 pub hir_crate
: Option
<&'a hir
::Crate
>,
318 pub ast_map
: Option
<&'a hir_map
::Map
<'ast
>>,
319 pub mir_map
: Option
<&'a MirMap
<'tcx
>>,
320 pub analysis
: Option
<&'a ty
::CrateAnalysis
<'a
>>,
321 pub tcx
: Option
<&'a TyCtxt
<'tcx
>>,
322 pub lcx
: Option
<&'a LoweringContext
<'a
>>,
323 pub trans
: Option
<&'a trans
::CrateTranslation
>,
326 impl<'a
, 'ast
, 'tcx
> CompileState
<'a
, 'ast
, 'tcx
> {
327 fn empty(input
: &'a Input
,
328 session
: &'a Session
,
329 out_dir
: &'a Option
<PathBuf
>)
330 -> CompileState
<'a
, 'ast
, 'tcx
> {
334 out_dir
: out_dir
.as_ref().map(|s
| &**s
),
338 output_filenames
: None
,
339 expanded_crate
: None
,
350 fn state_after_parse(input
: &'a Input
,
351 session
: &'a Session
,
352 out_dir
: &'a Option
<PathBuf
>,
353 krate
: &'a ast
::Crate
)
354 -> CompileState
<'a
, 'ast
, 'tcx
> {
355 CompileState { krate: Some(krate), ..CompileState::empty(input, session, out_dir) }
358 fn state_after_expand(input
: &'a Input
,
359 session
: &'a Session
,
360 out_dir
: &'a Option
<PathBuf
>,
361 expanded_crate
: &'a ast
::Crate
,
363 -> CompileState
<'a
, 'ast
, 'tcx
> {
365 crate_name
: Some(crate_name
),
366 expanded_crate
: Some(expanded_crate
),
367 ..CompileState
::empty(input
, session
, out_dir
)
371 fn state_after_write_deps(input
: &'a Input
,
372 session
: &'a Session
,
373 out_dir
: &'a Option
<PathBuf
>,
374 hir_map
: &'a hir_map
::Map
<'ast
>,
375 krate
: &'a ast
::Crate
,
376 hir_crate
: &'a hir
::Crate
,
378 lcx
: &'a LoweringContext
<'a
>)
379 -> CompileState
<'a
, 'ast
, 'tcx
> {
381 crate_name
: Some(crate_name
),
382 ast_map
: Some(hir_map
),
384 hir_crate
: Some(hir_crate
),
386 ..CompileState
::empty(input
, session
, out_dir
)
390 fn state_after_analysis(input
: &'a Input
,
391 session
: &'a Session
,
392 out_dir
: &'a Option
<PathBuf
>,
393 krate
: Option
<&'a ast
::Crate
>,
394 hir_crate
: &'a hir
::Crate
,
395 analysis
: &'a ty
::CrateAnalysis
,
396 mir_map
: Option
<&'a MirMap
<'tcx
>>,
397 tcx
: &'a TyCtxt
<'tcx
>,
398 lcx
: &'a LoweringContext
<'a
>,
400 -> CompileState
<'a
, 'ast
, 'tcx
> {
402 analysis
: Some(analysis
),
406 hir_crate
: Some(hir_crate
),
408 crate_name
: Some(crate_name
),
409 ..CompileState
::empty(input
, session
, out_dir
)
414 fn state_after_llvm(input
: &'a Input
,
415 session
: &'a Session
,
416 out_dir
: &'a Option
<PathBuf
>,
417 trans
: &'a trans
::CrateTranslation
)
418 -> CompileState
<'a
, 'ast
, 'tcx
> {
419 CompileState { trans: Some(trans), ..CompileState::empty(input, session, out_dir) }
423 pub fn phase_1_parse_input
<'a
>(sess
: &'a Session
,
424 cfg
: ast
::CrateConfig
,
426 -> PResult
<'a
, ast
::Crate
> {
427 // These may be left in an incoherent state after a previous compile.
428 // `clear_tables` and `get_ident_interner().clear()` can be used to free
429 // memory, but they do not restore the initial state.
430 syntax
::ext
::mtwt
::reset_tables();
431 token
::reset_ident_interner();
432 let continue_after_error
= sess
.opts
.continue_parse_after_error
;
433 sess
.diagnostic().set_continue_after_error(continue_after_error
);
435 let krate
= time(sess
.time_passes(), "parsing", || {
437 Input
::File(ref file
) => {
438 parse
::parse_crate_from_file(file
, cfg
.clone(), &sess
.parse_sess
)
440 Input
::Str { ref input, ref name }
=> {
441 parse
::parse_crate_from_source_str(name
.clone(),
449 sess
.diagnostic().set_continue_after_error(true);
451 if sess
.opts
.debugging_opts
.ast_json_noexpand
{
452 println
!("{}", json
::as_json(&krate
));
455 if sess
.opts
.debugging_opts
.input_stats
{
456 println
!("Lines of code: {}", sess
.codemap().count_lines());
457 println
!("Pre-expansion node count: {}", count_nodes(&krate
));
460 if let Some(ref s
) = sess
.opts
.debugging_opts
.show_span
{
461 syntax
::show_span
::run(sess
.diagnostic(), s
, &krate
);
467 fn count_nodes(krate
: &ast
::Crate
) -> usize {
468 let mut counter
= NodeCounter
::new();
469 visit
::walk_crate(&mut counter
, krate
);
473 // For continuing compilation after a parsed crate has been
476 /// Run the "early phases" of the compiler: initial `cfg` processing,
477 /// loading compiler plugins (including those from `addl_plugins`),
478 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
479 /// harness if one is to be provided and injection of a dependency on the
480 /// standard library and prelude.
482 /// Returns `None` if we're aborting after handling -W help.
483 pub fn phase_2_configure_and_expand(sess
: &Session
,
485 mut krate
: ast
::Crate
,
487 addl_plugins
: Option
<Vec
<String
>>)
488 -> Result
<ast
::Crate
, usize> {
489 let time_passes
= sess
.time_passes();
491 // strip before anything else because crate metadata may use #[cfg_attr]
492 // and so macros can depend on configuration variables, such as
494 // #[macro_use] #[cfg(foo)]
495 // mod bar { macro_rules! baz!(() => {{}}) }
497 // baz! should not use this definition unless foo is enabled.
499 let mut feature_gated_cfgs
= vec
![];
500 krate
= time(time_passes
, "configuration 1", || {
501 sess
.track_errors(|| {
502 syntax
::config
::strip_unconfigured_items(sess
.diagnostic(),
504 &mut feature_gated_cfgs
)
508 *sess
.crate_types
.borrow_mut() = collect_crate_types(sess
, &krate
.attrs
);
509 sess
.crate_disambiguator
.set(token
::intern(&compute_crate_disambiguator(sess
)));
511 time(time_passes
, "recursion limit", || {
512 middle
::recursion_limit
::update_recursion_limit(sess
, &krate
);
515 time(time_passes
, "gated macro checking", || {
516 sess
.track_errors(|| {
518 syntax
::feature_gate
::check_crate_macros(sess
.codemap(),
519 &sess
.parse_sess
.span_diagnostic
,
522 // these need to be set "early" so that expansion sees `quote` if enabled.
523 *sess
.features
.borrow_mut() = features
;
528 krate
= time(time_passes
, "crate injection", || {
529 syntax
::std_inject
::maybe_inject_crates_ref(krate
, sess
.opts
.alt_std_name
.clone())
532 let macros
= time(time_passes
,
534 || macro_import
::read_macro_defs(sess
, &cstore
, &krate
, crate_name
));
536 let mut addl_plugins
= Some(addl_plugins
);
537 let registrars
= time(time_passes
, "plugin loading", || {
538 plugin
::load
::load_plugins(sess
,
542 addl_plugins
.take().unwrap())
545 let mut registry
= Registry
::new(sess
, &krate
);
547 time(time_passes
, "plugin registration", || {
548 if sess
.features
.borrow().rustc_diagnostic_macros
{
549 registry
.register_macro("__diagnostic_used",
550 diagnostics
::plugin
::expand_diagnostic_used
);
551 registry
.register_macro("__register_diagnostic",
552 diagnostics
::plugin
::expand_register_diagnostic
);
553 registry
.register_macro("__build_diagnostic_array",
554 diagnostics
::plugin
::expand_build_diagnostic_array
);
557 for registrar
in registrars
{
558 registry
.args_hidden
= Some(registrar
.args
);
559 (registrar
.fun
)(&mut registry
);
563 let Registry
{ syntax_exts
, early_lint_passes
, late_lint_passes
, lint_groups
,
564 llvm_passes
, attributes
, mir_passes
, .. } = registry
;
566 sess
.track_errors(|| {
567 let mut ls
= sess
.lint_store
.borrow_mut();
568 for pass
in early_lint_passes
{
569 ls
.register_early_pass(Some(sess
), true, pass
);
571 for pass
in late_lint_passes
{
572 ls
.register_late_pass(Some(sess
), true, pass
);
575 for (name
, to
) in lint_groups
{
576 ls
.register_group(Some(sess
), true, name
, to
);
579 *sess
.plugin_llvm_passes
.borrow_mut() = llvm_passes
;
580 sess
.mir_passes
.borrow_mut().extend(mir_passes
);
581 *sess
.plugin_attributes
.borrow_mut() = attributes
.clone();
584 // Lint plugins are registered; now we can process command line flags.
585 if sess
.opts
.describe_lints
{
586 super::describe_lints(&sess
.lint_store
.borrow(), true);
589 sess
.track_errors(|| sess
.lint_store
.borrow_mut().process_command_line(sess
))?
;
591 krate
= time(time_passes
, "expansion", || {
592 // Windows dlls do not have rpaths, so they don't know how to find their
593 // dependencies. It's up to us to tell the system where to find all the
594 // dependent dlls. Note that this uses cfg!(windows) as opposed to
595 // targ_cfg because syntax extensions are always loaded for the host
596 // compiler, not for the target.
597 let mut _old_path
= OsString
::new();
599 _old_path
= env
::var_os("PATH").unwrap_or(_old_path
);
600 let mut new_path
= sess
.host_filesearch(PathKind
::All
)
601 .get_dylib_search_paths();
602 new_path
.extend(env
::split_paths(&_old_path
));
603 env
::set_var("PATH", &env
::join_paths(new_path
).unwrap());
605 let features
= sess
.features
.borrow();
606 let cfg
= syntax
::ext
::expand
::ExpansionConfig
{
607 crate_name
: crate_name
.to_string(),
608 features
: Some(&features
),
609 recursion_limit
: sess
.recursion_limit
.get(),
610 trace_mac
: sess
.opts
.debugging_opts
.trace_macros
,
612 let mut ecx
= syntax
::ext
::base
::ExtCtxt
::new(&sess
.parse_sess
,
613 krate
.config
.clone(),
615 &mut feature_gated_cfgs
);
616 syntax_ext
::register_builtins(&mut ecx
.syntax_env
);
617 let (ret
, macro_names
) = syntax
::ext
::expand
::expand_crate(ecx
,
622 env
::set_var("PATH", &_old_path
);
624 *sess
.available_macros
.borrow_mut() = macro_names
;
628 // Needs to go *after* expansion to be able to check the results
629 // of macro expansion. This runs before #[cfg] to try to catch as
630 // much as possible (e.g. help the programmer avoid platform
631 // specific differences)
632 time(time_passes
, "complete gated feature checking 1", || {
633 sess
.track_errors(|| {
634 let features
= syntax
::feature_gate
::check_crate(sess
.codemap(),
635 &sess
.parse_sess
.span_diagnostic
,
638 sess
.opts
.unstable_features
);
639 *sess
.features
.borrow_mut() = features
;
643 // JBC: make CFG processing part of expansion to avoid this problem:
645 // strip again, in case expansion added anything with a #[cfg].
646 krate
= sess
.track_errors(|| {
647 let krate
= time(time_passes
, "configuration 2", || {
648 syntax
::config
::strip_unconfigured_items(sess
.diagnostic(),
650 &mut feature_gated_cfgs
)
653 time(time_passes
, "gated configuration checking", || {
654 let features
= sess
.features
.borrow();
655 feature_gated_cfgs
.sort();
656 feature_gated_cfgs
.dedup();
657 for cfg
in &feature_gated_cfgs
{
658 cfg
.check_and_emit(sess
.diagnostic(), &features
, sess
.codemap());
665 krate
= time(time_passes
, "maybe building test harness", || {
666 syntax
::test
::modify_for_testing(&sess
.parse_sess
, &sess
.opts
.cfg
, krate
, sess
.diagnostic())
669 krate
= time(time_passes
,
671 || syntax
::std_inject
::maybe_inject_prelude(&sess
.parse_sess
, krate
));
674 "checking that all macro invocations are gone",
675 || syntax
::ext
::expand
::check_for_macros(&sess
.parse_sess
, &krate
));
678 "checking for inline asm in case the target doesn't support it",
679 || no_asm
::check_crate(sess
, &krate
));
681 // One final feature gating of the true AST that gets compiled
682 // later, to make sure we've got everything (e.g. configuration
683 // can insert new attributes via `cfg_attr`)
684 time(time_passes
, "complete gated feature checking 2", || {
685 sess
.track_errors(|| {
686 let features
= syntax
::feature_gate
::check_crate(sess
.codemap(),
687 &sess
.parse_sess
.span_diagnostic
,
690 sess
.opts
.unstable_features
);
691 *sess
.features
.borrow_mut() = features
;
696 "const fn bodies and arguments",
697 || const_fn
::check_crate(sess
, &krate
))?
;
699 if sess
.opts
.debugging_opts
.input_stats
{
700 println
!("Post-expansion node count: {}", count_nodes(&krate
));
706 pub fn assign_node_ids(sess
: &Session
, krate
: ast
::Crate
) -> ast
::Crate
{
707 struct NodeIdAssigner
<'a
> {
711 impl<'a
> Folder
for NodeIdAssigner
<'a
> {
712 fn new_id(&mut self, old_id
: ast
::NodeId
) -> ast
::NodeId
{
713 assert_eq
!(old_id
, ast
::DUMMY_NODE_ID
);
714 self.sess
.next_node_id()
718 let krate
= time(sess
.time_passes(),
719 "assigning node ids",
720 || NodeIdAssigner { sess: sess }
.fold_crate(krate
));
722 if sess
.opts
.debugging_opts
.ast_json
{
723 println
!("{}", json
::as_json(&krate
));
729 pub fn make_map
<'ast
>(sess
: &Session
,
730 forest
: &'ast
mut hir_map
::Forest
)
731 -> hir_map
::Map
<'ast
> {
732 // Construct the HIR map
733 time(sess
.time_passes(),
735 move || hir_map
::map_crate(forest
))
738 /// Run the resolution, typechecking, region checking and other
739 /// miscellaneous analysis passes on the crate. Return various
740 /// structures carrying the results of the analysis.
741 pub fn phase_3_run_analysis_passes
<'tcx
, F
, R
>(sess
: &'tcx Session
,
743 hir_map
: hir_map
::Map
<'tcx
>,
744 arenas
: &'tcx ty
::CtxtArenas
<'tcx
>,
746 make_glob_map
: resolve
::MakeGlobMap
,
749 where F
: FnOnce(&TyCtxt
<'tcx
>, Option
<MirMap
<'tcx
>>, ty
::CrateAnalysis
, CompileResult
) -> R
751 macro_rules
! try_with_f
{
752 ($e
: expr
, ($t
: expr
, $m
: expr
, $a
: expr
)) => {
756 f($t
, $m
, $a
, Err(x
));
763 let time_passes
= sess
.time_passes();
766 "external crate/lib resolution",
767 || LocalCrateReader
::new(sess
, cstore
, &hir_map
, name
).read_crates());
769 let lang_items
= time(time_passes
, "language item collection", || {
770 sess
.track_errors(|| {
771 middle
::lang_items
::collect_language_items(&sess
, &hir_map
)
775 let resolve
::CrateMap
{
781 } = time(time_passes
,
783 || resolve
::resolve_crate(sess
, &hir_map
, make_glob_map
));
785 let mut analysis
= ty
::CrateAnalysis
{
786 export_map
: export_map
,
787 access_levels
: AccessLevels
::default(),
788 reachable
: NodeSet(),
793 let named_region_map
= time(time_passes
,
794 "lifetime resolution",
795 || middle
::resolve_lifetime
::krate(sess
,
797 &def_map
.borrow()))?
;
800 "looking for entry point",
801 || middle
::entry
::find_entry_point(sess
, &hir_map
));
803 sess
.plugin_registrar_fn
.set(time(time_passes
, "looking for plugin registrar", || {
804 plugin
::build
::find_plugin_registrar(sess
.diagnostic(), &hir_map
)
807 let region_map
= time(time_passes
,
809 || middle
::region
::resolve_crate(sess
, &hir_map
));
813 || loops
::check_crate(sess
, &hir_map
));
816 "static item recursion checking",
817 || static_recursion
::check_crate(sess
, &def_map
.borrow(), &hir_map
))?
;
819 let index
= stability
::Index
::new(&hir_map
);
821 TyCtxt
::create_and_enter(sess
,
834 || rustc_incremental
::load_dep_graph(tcx
));
836 // passes are timed inside typeck
837 try_with_f
!(typeck
::check_crate(tcx
, trait_map
), (tcx
, None
, analysis
));
841 || consts
::check_crate(tcx
));
843 analysis
.access_levels
=
844 time(time_passes
, "privacy checking", || {
845 rustc_privacy
::check_crate(tcx
, &analysis
.export_map
)
848 // Do not move this check past lint
849 time(time_passes
, "stability index", || {
850 tcx
.stability
.borrow_mut().build(tcx
, &analysis
.access_levels
)
854 "intrinsic checking",
855 || middle
::intrinsicck
::check_crate(tcx
));
859 || middle
::effect
::check_crate(tcx
));
863 || check_match
::check_crate(tcx
));
865 // this must run before MIR dump, because
866 // "not all control paths return a value" is reported here.
868 // maybe move the check to a MIR pass?
871 || middle
::liveness
::check_crate(tcx
));
875 || rvalues
::check_crate(tcx
));
880 || mir
::mir_map
::build_mir_for_crate(tcx
));
882 time(time_passes
, "MIR passes", || {
883 let mut passes
= sess
.mir_passes
.borrow_mut();
884 // Push all the built-in passes.
885 passes
.push_pass(box mir
::transform
::remove_dead_blocks
::RemoveDeadBlocks
);
886 passes
.push_pass(box mir
::transform
::type_check
::TypeckMir
);
887 passes
.push_pass(box mir
::transform
::simplify_cfg
::SimplifyCfg
);
888 passes
.push_pass(box mir
::transform
::remove_dead_blocks
::RemoveDeadBlocks
);
889 // And run everything.
890 passes
.run_passes(tcx
, &mut mir_map
);
895 || borrowck
::check_crate(tcx
, &mir_map
));
897 // Avoid overwhelming user with errors if type checking failed.
898 // I'm not sure how helpful this is, to be honest, but it avoids
900 // lot of annoying errors in the compile-fail tests (basically,
901 // lint warnings and so on -- kindck used to do this abort, but
902 // kindck is gone now). -nmatsakis
903 if sess
.err_count() > 0 {
904 return Ok(f(tcx
, Some(mir_map
), analysis
, Err(sess
.err_count())));
909 "reachability checking",
910 || reachable
::find_reachable(tcx
, &analysis
.access_levels
));
912 time(time_passes
, "death checking", || {
913 middle
::dead
::check_crate(tcx
, &analysis
.access_levels
);
916 let ref lib_features_used
=
918 "stability checking",
919 || stability
::check_unstable_api_usage(tcx
));
921 time(time_passes
, "unused lib feature checking", || {
922 stability
::check_unused_or_stable_features(&tcx
.sess
,
928 || lint
::check_crate(tcx
, &analysis
.access_levels
));
930 // The above three passes generate errors w/o aborting
931 if sess
.err_count() > 0 {
932 return Ok(f(tcx
, Some(mir_map
), analysis
, Err(sess
.err_count())));
935 Ok(f(tcx
, Some(mir_map
), analysis
, Ok(())))
939 /// Run the translation phase to LLVM, after which the AST and analysis can
940 pub fn phase_4_translate_to_llvm
<'tcx
>(tcx
: &TyCtxt
<'tcx
>,
941 mut mir_map
: MirMap
<'tcx
>,
942 analysis
: ty
::CrateAnalysis
) -> trans
::CrateTranslation
{
943 let time_passes
= tcx
.sess
.time_passes();
946 "resolving dependency formats",
947 || dependency_format
::calculate(&tcx
.sess
));
949 // Run the passes that transform the MIR into a more suitable for translation
951 time(time_passes
, "Prepare MIR codegen passes", || {
952 let mut passes
= ::rustc
::mir
::transform
::Passes
::new();
953 passes
.push_pass(box mir
::transform
::no_landing_pads
::NoLandingPads
);
954 passes
.push_pass(box mir
::transform
::remove_dead_blocks
::RemoveDeadBlocks
);
955 passes
.push_pass(box mir
::transform
::erase_regions
::EraseRegions
);
956 passes
.push_pass(box mir
::transform
::break_critical_edges
::BreakCriticalEdges
);
957 passes
.run_passes(tcx
, &mut mir_map
);
963 move || trans
::trans_crate(tcx
, &mir_map
, analysis
));
967 move || rustc_incremental
::assert_dep_graph(tcx
));
970 "serialize dep graph",
971 move || rustc_incremental
::save_dep_graph(tcx
));
976 /// Run LLVM itself, producing a bitcode file, assembly file or object file
977 /// as a side effect.
978 pub fn phase_5_run_llvm_passes(sess
: &Session
,
979 trans
: &trans
::CrateTranslation
,
980 outputs
: &OutputFilenames
) -> CompileResult
{
981 if sess
.opts
.cg
.no_integrated_as
{
982 let mut map
= HashMap
::new();
983 map
.insert(OutputType
::Assembly
, None
);
984 time(sess
.time_passes(),
986 || write
::run_passes(sess
, trans
, &map
, outputs
));
988 write
::run_assembler(sess
, outputs
);
990 // Remove assembly source, unless --save-temps was specified
991 if !sess
.opts
.cg
.save_temps
{
992 fs
::remove_file(&outputs
.temp_path(OutputType
::Assembly
)).unwrap();
995 time(sess
.time_passes(),
997 || write
::run_passes(sess
, trans
, &sess
.opts
.output_types
, outputs
));
1000 if sess
.err_count() > 0 {
1001 Err(sess
.err_count())
1007 /// Run the linker on any artifacts that resulted from the LLVM run.
1008 /// This should produce either a finished executable or library.
1009 pub fn phase_6_link_output(sess
: &Session
,
1010 trans
: &trans
::CrateTranslation
,
1011 outputs
: &OutputFilenames
) {
1012 time(sess
.time_passes(),
1014 || link
::link_binary(sess
, trans
, outputs
, &trans
.link
.crate_name
));
1017 fn escape_dep_filename(filename
: &str) -> String
{
1018 // Apparently clang and gcc *only* escape spaces:
1019 // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
1020 filename
.replace(" ", "\\ ")
1023 fn write_out_deps(sess
: &Session
, outputs
: &OutputFilenames
, id
: &str) {
1024 let mut out_filenames
= Vec
::new();
1025 for output_type
in sess
.opts
.output_types
.keys() {
1026 let file
= outputs
.path(*output_type
);
1027 match *output_type
{
1028 OutputType
::Exe
=> {
1029 for output
in sess
.crate_types
.borrow().iter() {
1030 let p
= link
::filename_for_input(sess
, *output
, id
, outputs
);
1031 out_filenames
.push(p
);
1035 out_filenames
.push(file
);
1040 // Write out dependency rules to the dep-info file if requested
1041 if !sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
) {
1044 let deps_filename
= outputs
.path(OutputType
::DepInfo
);
1047 (|| -> io
::Result
<()> {
1048 // Build a list of files used to compile the output and
1049 // write Makefile-compatible dependency rules
1050 let files
: Vec
<String
> = sess
.codemap()
1054 .filter(|fmap
| fmap
.is_real_file())
1055 .filter(|fmap
| !fmap
.is_imported())
1056 .map(|fmap
| escape_dep_filename(&fmap
.name
))
1058 let mut file
= fs
::File
::create(&deps_filename
)?
;
1059 for path
in &out_filenames
{
1060 write
!(file
, "{}: {}\n\n", path
.display(), files
.join(" "))?
;
1063 // Emit a fake target for each input file to the compilation. This
1064 // prevents `make` from spitting out an error if a file is later
1065 // deleted. For more info see #28735
1067 writeln
!(file
, "{}:", path
)?
;
1075 sess
.fatal(&format
!("error writing dependencies to `{}`: {}",
1076 deps_filename
.display(),
1082 pub fn collect_crate_types(session
: &Session
, attrs
: &[ast
::Attribute
]) -> Vec
<config
::CrateType
> {
1083 // Unconditionally collect crate types from attributes to make them used
1084 let attr_types
: Vec
<config
::CrateType
> =
1087 if a
.check_name("crate_type") {
1088 match a
.value_str() {
1089 Some(ref n
) if *n
== "rlib" => {
1090 Some(config
::CrateTypeRlib
)
1092 Some(ref n
) if *n
== "dylib" => {
1093 Some(config
::CrateTypeDylib
)
1095 Some(ref n
) if *n
== "lib" => {
1096 Some(config
::default_lib_output())
1098 Some(ref n
) if *n
== "staticlib" => {
1099 Some(config
::CrateTypeStaticlib
)
1101 Some(ref n
) if *n
== "bin" => Some(config
::CrateTypeExecutable
),
1103 session
.add_lint(lint
::builtin
::UNKNOWN_CRATE_TYPES
,
1106 "invalid `crate_type` value".to_string());
1110 session
.struct_span_err(a
.span
, "`crate_type` requires a value")
1111 .note("for example: `#![crate_type=\"lib\"]`")
1122 // If we're generating a test executable, then ignore all other output
1123 // styles at all other locations
1124 if session
.opts
.test
{
1125 return vec
![config
::CrateTypeExecutable
];
1128 // Only check command line flags if present. If no types are specified by
1129 // command line, then reuse the empty `base` Vec to hold the types that
1130 // will be found in crate attributes.
1131 let mut base
= session
.opts
.crate_types
.clone();
1132 if base
.is_empty() {
1133 base
.extend(attr_types
);
1134 if base
.is_empty() {
1135 base
.push(link
::default_output_for_target(session
));
1142 .filter(|crate_type
| {
1143 let res
= !link
::invalid_output_for_target(session
, *crate_type
);
1146 session
.warn(&format
!("dropping unsupported crate type `{}` for target `{}`",
1148 session
.opts
.target_triple
));
1156 pub fn compute_crate_disambiguator(session
: &Session
) -> String
{
1157 let mut hasher
= Sha256
::new();
1159 let mut metadata
= session
.opts
.cg
.metadata
.clone();
1160 // We don't want the crate_disambiguator to dependent on the order
1161 // -C metadata arguments, so sort them:
1163 // Every distinct -C metadata value is only incorporated once:
1166 hasher
.input_str("metadata");
1167 for s
in &metadata
{
1168 // Also incorporate the length of a metadata string, so that we generate
1169 // different values for `-Cmetadata=ab -Cmetadata=c` and
1170 // `-Cmetadata=a -Cmetadata=bc`
1171 hasher
.input_str(&format
!("{}", s
.len())[..]);
1172 hasher
.input_str(&s
[..]);
1175 let mut hash
= hasher
.result_str();
1177 // If this is an executable, add a special suffix, so that we don't get
1178 // symbol conflicts when linking against a library of the same name.
1179 if session
.crate_types
.borrow().contains(&config
::CrateTypeExecutable
) {
1180 hash
.push_str("-exe");
1186 pub fn build_output_filenames(input
: &Input
,
1187 odir
: &Option
<PathBuf
>,
1188 ofile
: &Option
<PathBuf
>,
1189 attrs
: &[ast
::Attribute
],
1191 -> OutputFilenames
{
1194 // "-" as input file will cause the parser to read from stdin so we
1195 // have to make up a name
1196 // We want to toss everything after the final '.'
1197 let dirpath
= match *odir
{
1198 Some(ref d
) => d
.clone(),
1199 None
=> PathBuf
::new(),
1202 // If a crate name is present, we use it as the link name
1203 let stem
= sess
.opts
1206 .or_else(|| attr
::find_crate_name(attrs
).map(|n
| n
.to_string()))
1207 .unwrap_or(input
.filestem());
1210 out_directory
: dirpath
,
1212 single_output_file
: None
,
1213 extra
: sess
.opts
.cg
.extra_filename
.clone(),
1214 outputs
: sess
.opts
.output_types
.clone(),
1218 Some(ref out_file
) => {
1219 let unnamed_output_types
= sess
.opts
1222 .filter(|a
| a
.is_none())
1224 let ofile
= if unnamed_output_types
> 1 {
1225 sess
.warn("ignoring specified output filename because multiple outputs were \
1229 Some(out_file
.clone())
1232 sess
.warn("ignoring --out-dir flag due to -o flag.");
1235 let cur_dir
= Path
::new("");
1238 out_directory
: out_file
.parent().unwrap_or(cur_dir
).to_path_buf(),
1239 out_filestem
: out_file
.file_stem()
1240 .unwrap_or(OsStr
::new(""))
1244 single_output_file
: ofile
,
1245 extra
: sess
.opts
.cg
.extra_filename
.clone(),
1246 outputs
: sess
.opts
.output_types
.clone(),