]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
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. | |
10 | ||
54a0048b | 11 | use rustc::hir; |
a7813a04 XL |
12 | use rustc::hir::{map as hir_map, FreevarMap, TraitMap}; |
13 | use rustc::hir::def::DefMap; | |
3157f602 | 14 | use rustc::hir::lowering::lower_crate; |
c30ab7b3 SL |
15 | use rustc_data_structures::blake2b::Blake2bHasher; |
16 | use rustc_data_structures::fmt_wrap::FmtWrap; | |
17 | use rustc::ty::util::ArchIndependentHasher; | |
e9174d1e | 18 | use rustc_mir as mir; |
7453a54e | 19 | use rustc::session::{Session, CompileResult, compile_result_from_err_count}; |
5bcae85e SL |
20 | use rustc::session::config::{self, Input, OutputFilenames, OutputType, |
21 | OutputTypes}; | |
1a4d82fc JJ |
22 | use rustc::session::search_paths::PathKind; |
23 | use rustc::lint; | |
54a0048b | 24 | use rustc::middle::{self, dependency_format, stability, reachable}; |
7453a54e | 25 | use rustc::middle::privacy::AccessLevels; |
54a0048b | 26 | use rustc::ty::{self, TyCtxt}; |
1a4d82fc | 27 | use rustc::util::common::time; |
7453a54e | 28 | use rustc::util::nodemap::NodeSet; |
1a4d82fc | 29 | use rustc_borrowck as borrowck; |
9e0c209e | 30 | use rustc_incremental::{self, IncrementalHashesMap}; |
3157f602 | 31 | use rustc_resolve::{MakeGlobMap, Resolver}; |
9e0c209e | 32 | use rustc_metadata::creader::CrateLoader; |
92a42be0 | 33 | use rustc_metadata::cstore::CStore; |
3157f602 | 34 | use rustc_trans::back::{link, write}; |
54a0048b | 35 | use rustc_trans as trans; |
1a4d82fc | 36 | use rustc_typeck as typeck; |
85aaf69f | 37 | use rustc_privacy; |
92a42be0 SL |
38 | use rustc_plugin::registry::Registry; |
39 | use rustc_plugin as plugin; | |
c30ab7b3 SL |
40 | use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, |
41 | static_recursion, hir_stats}; | |
54a0048b | 42 | use rustc_const_eval::check_match; |
85aaf69f | 43 | use super::Compilation; |
1a4d82fc JJ |
44 | |
45 | use serialize::json; | |
46 | ||
85aaf69f | 47 | use std::env; |
9e0c209e | 48 | use std::mem; |
62682a34 | 49 | use std::ffi::{OsString, OsStr}; |
c34b1796 AL |
50 | use std::fs; |
51 | use std::io::{self, Write}; | |
52 | use std::path::{Path, PathBuf}; | |
3157f602 | 53 | use syntax::{ast, diagnostics, visit}; |
9e0c209e SL |
54 | use syntax::attr; |
55 | use syntax::ext::base::ExtCtxt; | |
54a0048b | 56 | use syntax::parse::{self, PResult, token}; |
92a42be0 | 57 | use syntax::util::node_count::NodeCounter; |
1a4d82fc | 58 | use syntax; |
9cc50fc6 | 59 | use syntax_ext; |
1a4d82fc | 60 | |
9e0c209e SL |
61 | use derive_registrar; |
62 | ||
a7813a04 XL |
63 | #[derive(Clone)] |
64 | pub struct Resolutions { | |
3157f602 | 65 | pub def_map: DefMap, |
a7813a04 XL |
66 | pub freevars: FreevarMap, |
67 | pub trait_map: TraitMap, | |
68 | pub maybe_unused_trait_imports: NodeSet, | |
69 | } | |
70 | ||
7453a54e | 71 | pub fn compile_input(sess: &Session, |
92a42be0 | 72 | cstore: &CStore, |
1a4d82fc | 73 | input: &Input, |
c34b1796 AL |
74 | outdir: &Option<PathBuf>, |
75 | output: &Option<PathBuf>, | |
85aaf69f | 76 | addl_plugins: Option<Vec<String>>, |
7453a54e SL |
77 | control: &CompileController) -> CompileResult { |
78 | macro_rules! controller_entry_point { | |
79 | ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ | |
a7813a04 | 80 | let state = &mut $make_state; |
7453a54e SL |
81 | let phase_result: &CompileResult = &$phase_result; |
82 | if phase_result.is_ok() || control.$point.run_callback_on_error { | |
83 | (control.$point.callback)(state); | |
84 | } | |
85 | ||
86 | if control.$point.stop == Compilation::Stop { | |
87 | return compile_result_from_err_count($tsess.err_count()); | |
88 | } | |
89 | }} | |
90 | } | |
85aaf69f | 91 | |
1a4d82fc JJ |
92 | // We need nested scopes here, because the intermediate results can keep |
93 | // large chunks of memory alive and we want to free them as soon as | |
94 | // possible to keep the peak memory usage low | |
9e0c209e | 95 | let (outputs, trans) = { |
c30ab7b3 | 96 | let krate = match phase_1_parse_input(sess, input) { |
3157f602 XL |
97 | Ok(krate) => krate, |
98 | Err(mut parse_error) => { | |
99 | parse_error.emit(); | |
100 | return Err(1); | |
101 | } | |
102 | }; | |
85aaf69f | 103 | |
9e0c209e | 104 | let (krate, registry) = { |
a7813a04 XL |
105 | let mut compile_state = CompileState::state_after_parse(input, |
106 | sess, | |
107 | outdir, | |
108 | output, | |
109 | krate, | |
110 | &cstore); | |
85aaf69f | 111 | controller_entry_point!(after_parse, |
d9579d0f | 112 | sess, |
a7813a04 | 113 | compile_state, |
7453a54e | 114 | Ok(())); |
1a4d82fc | 115 | |
9e0c209e | 116 | (compile_state.krate.unwrap(), compile_state.registry) |
1a4d82fc JJ |
117 | }; |
118 | ||
3157f602 | 119 | let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); |
5bcae85e | 120 | let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input); |
3157f602 XL |
121 | let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { |
122 | phase_2_configure_and_expand( | |
9e0c209e | 123 | sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map, |
3157f602 XL |
124 | |expanded_crate| { |
125 | let mut state = CompileState::state_after_expand( | |
5bcae85e | 126 | input, sess, outdir, output, &cstore, expanded_crate, &crate_name, |
3157f602 XL |
127 | ); |
128 | controller_entry_point!(after_expand, sess, state, Ok(())); | |
129 | Ok(()) | |
130 | } | |
131 | )? | |
a7813a04 | 132 | }; |
92a42be0 | 133 | |
5bcae85e | 134 | write_out_deps(sess, &outputs, &crate_name); |
92a42be0 | 135 | |
85aaf69f | 136 | let arenas = ty::CtxtArenas::new(); |
1a4d82fc | 137 | |
a7813a04 | 138 | // Construct the HIR map |
a7813a04 XL |
139 | let hir_map = time(sess.time_passes(), |
140 | "indexing hir", | |
3157f602 | 141 | || hir_map::map_crate(&mut hir_forest, defs)); |
85aaf69f | 142 | |
7453a54e SL |
143 | { |
144 | let _ignore = hir_map.dep_graph.in_ignore(); | |
a7813a04 | 145 | controller_entry_point!(after_hir_lowering, |
7453a54e | 146 | sess, |
a7813a04 XL |
147 | CompileState::state_after_hir_lowering(input, |
148 | sess, | |
149 | outdir, | |
150 | output, | |
151 | &arenas, | |
152 | &cstore, | |
153 | &hir_map, | |
154 | &analysis, | |
155 | &resolutions, | |
156 | &expanded_crate, | |
157 | &hir_map.krate(), | |
5bcae85e | 158 | &crate_name), |
7453a54e SL |
159 | Ok(())); |
160 | } | |
85aaf69f | 161 | |
b039eaaf | 162 | time(sess.time_passes(), "attribute checking", || { |
54a0048b | 163 | hir::check_attr::check_crate(sess, &expanded_crate); |
b039eaaf SL |
164 | }); |
165 | ||
a7813a04 | 166 | let opt_crate = if keep_ast(sess) { |
9cc50fc6 SL |
167 | Some(&expanded_crate) |
168 | } else { | |
169 | drop(expanded_crate); | |
170 | None | |
171 | }; | |
172 | ||
54a0048b | 173 | phase_3_run_analysis_passes(sess, |
54a0048b | 174 | hir_map, |
a7813a04 XL |
175 | analysis, |
176 | resolutions, | |
54a0048b | 177 | &arenas, |
5bcae85e | 178 | &crate_name, |
c30ab7b3 | 179 | |tcx, analysis, incremental_hashes_map, result| { |
7453a54e SL |
180 | { |
181 | // Eventually, we will want to track plugins. | |
182 | let _ignore = tcx.dep_graph.in_ignore(); | |
183 | ||
a7813a04 XL |
184 | let mut state = CompileState::state_after_analysis(input, |
185 | sess, | |
186 | outdir, | |
187 | output, | |
188 | opt_crate, | |
189 | tcx.map.krate(), | |
190 | &analysis, | |
a7813a04 | 191 | tcx, |
5bcae85e | 192 | &crate_name); |
a7813a04 | 193 | (control.after_analysis.callback)(&mut state); |
7453a54e SL |
194 | |
195 | if control.after_analysis.stop == Compilation::Stop { | |
a7813a04 | 196 | return result.and_then(|_| Err(0usize)); |
7453a54e SL |
197 | } |
198 | } | |
62682a34 | 199 | |
54a0048b | 200 | result?; |
7453a54e SL |
201 | |
202 | if log_enabled!(::log::INFO) { | |
203 | println!("Pre-trans"); | |
204 | tcx.print_debug_stats(); | |
205 | } | |
c30ab7b3 | 206 | let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); |
7453a54e SL |
207 | |
208 | if log_enabled!(::log::INFO) { | |
209 | println!("Post-trans"); | |
210 | tcx.print_debug_stats(); | |
211 | } | |
212 | ||
213 | // Discard interned strings as they are no longer required. | |
5bcae85e | 214 | token::clear_ident_interner(); |
7453a54e | 215 | |
9e0c209e | 216 | Ok((outputs, trans)) |
54a0048b | 217 | })?? |
62682a34 SL |
218 | }; |
219 | ||
9e0c209e | 220 | let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); |
85aaf69f SL |
221 | |
222 | controller_entry_point!(after_llvm, | |
d9579d0f | 223 | sess, |
a7813a04 | 224 | CompileState::state_after_llvm(input, sess, outdir, output, &trans), |
7453a54e | 225 | phase5_result); |
54a0048b | 226 | phase5_result?; |
7453a54e | 227 | |
3157f602 XL |
228 | write::cleanup_llvm(&trans); |
229 | ||
7453a54e | 230 | phase_6_link_output(sess, &trans, &outputs); |
85aaf69f | 231 | |
9e0c209e SL |
232 | // Now that we won't touch anything in the incremental compilation directory |
233 | // any more, we can finalize it (which involves renaming it) | |
234 | rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash); | |
235 | ||
236 | if sess.opts.debugging_opts.perf_stats { | |
237 | sess.print_perf_stats(); | |
238 | } | |
239 | ||
3157f602 XL |
240 | controller_entry_point!(compilation_done, |
241 | sess, | |
242 | CompileState::state_when_compilation_done(input, sess, outdir, output), | |
243 | Ok(())); | |
244 | ||
7453a54e | 245 | Ok(()) |
1a4d82fc JJ |
246 | } |
247 | ||
5bcae85e SL |
248 | fn keep_hygiene_data(sess: &Session) -> bool { |
249 | sess.opts.debugging_opts.keep_hygiene_data | |
a7813a04 XL |
250 | } |
251 | ||
252 | fn keep_ast(sess: &Session) -> bool { | |
253 | sess.opts.debugging_opts.keep_ast || | |
254 | sess.opts.debugging_opts.save_analysis || | |
9e0c209e SL |
255 | sess.opts.debugging_opts.save_analysis_csv || |
256 | sess.opts.debugging_opts.save_analysis_api | |
a7813a04 XL |
257 | } |
258 | ||
1a4d82fc JJ |
259 | /// The name used for source code that doesn't originate in a file |
260 | /// (e.g. source from stdin or a string) | |
261 | pub fn anon_src() -> String { | |
262 | "<anon>".to_string() | |
263 | } | |
264 | ||
265 | pub fn source_name(input: &Input) -> String { | |
266 | match *input { | |
267 | // FIXME (#9639): This needs to handle non-utf8 paths | |
c34b1796 | 268 | Input::File(ref ifile) => ifile.to_str().unwrap().to_string(), |
54a0048b | 269 | Input::Str { ref name, .. } => name.clone(), |
1a4d82fc JJ |
270 | } |
271 | } | |
272 | ||
85aaf69f SL |
273 | /// CompileController is used to customise compilation, it allows compilation to |
274 | /// be stopped and/or to call arbitrary code at various points in compilation. | |
275 | /// It also allows for various flags to be set to influence what information gets | |
276 | /// collected during compilation. | |
277 | /// | |
278 | /// This is a somewhat higher level controller than a Session - the Session | |
279 | /// controls what happens in each phase, whereas the CompileController controls | |
280 | /// whether a phase is run at all and whether other code (from outside the | |
281 | /// the compiler) is run between phases. | |
282 | /// | |
283 | /// Note that if compilation is set to stop and a callback is provided for a | |
284 | /// given entry point, the callback is called before compilation is stopped. | |
285 | /// | |
286 | /// Expect more entry points to be added in the future. | |
287 | pub struct CompileController<'a> { | |
288 | pub after_parse: PhaseController<'a>, | |
289 | pub after_expand: PhaseController<'a>, | |
a7813a04 | 290 | pub after_hir_lowering: PhaseController<'a>, |
85aaf69f SL |
291 | pub after_analysis: PhaseController<'a>, |
292 | pub after_llvm: PhaseController<'a>, | |
3157f602 | 293 | pub compilation_done: PhaseController<'a>, |
85aaf69f | 294 | |
3157f602 | 295 | pub make_glob_map: MakeGlobMap, |
85aaf69f SL |
296 | } |
297 | ||
298 | impl<'a> CompileController<'a> { | |
299 | pub fn basic() -> CompileController<'a> { | |
300 | CompileController { | |
301 | after_parse: PhaseController::basic(), | |
302 | after_expand: PhaseController::basic(), | |
a7813a04 | 303 | after_hir_lowering: PhaseController::basic(), |
85aaf69f SL |
304 | after_analysis: PhaseController::basic(), |
305 | after_llvm: PhaseController::basic(), | |
3157f602 XL |
306 | compilation_done: PhaseController::basic(), |
307 | make_glob_map: MakeGlobMap::No, | |
85aaf69f SL |
308 | } |
309 | } | |
310 | } | |
311 | ||
312 | pub struct PhaseController<'a> { | |
313 | pub stop: Compilation, | |
7453a54e SL |
314 | // If true then the compiler will try to run the callback even if the phase |
315 | // ends with an error. Note that this is not always possible. | |
316 | pub run_callback_on_error: bool, | |
a7813a04 | 317 | pub callback: Box<Fn(&mut CompileState) + 'a>, |
85aaf69f SL |
318 | } |
319 | ||
320 | impl<'a> PhaseController<'a> { | |
321 | pub fn basic() -> PhaseController<'a> { | |
322 | PhaseController { | |
323 | stop: Compilation::Continue, | |
7453a54e | 324 | run_callback_on_error: false, |
85aaf69f SL |
325 | callback: box |_| {}, |
326 | } | |
327 | } | |
328 | } | |
329 | ||
330 | /// State that is passed to a callback. What state is available depends on when | |
331 | /// during compilation the callback is made. See the various constructor methods | |
332 | /// (`state_*`) in the impl to see which data is provided for any given entry point. | |
a7813a04 | 333 | pub struct CompileState<'a, 'b, 'ast: 'a, 'tcx: 'b> where 'ast: 'tcx { |
85aaf69f | 334 | pub input: &'a Input, |
a7813a04 XL |
335 | pub session: &'ast Session, |
336 | pub krate: Option<ast::Crate>, | |
9e0c209e | 337 | pub registry: Option<Registry<'a>>, |
a7813a04 | 338 | pub cstore: Option<&'a CStore>, |
85aaf69f SL |
339 | pub crate_name: Option<&'a str>, |
340 | pub output_filenames: Option<&'a OutputFilenames>, | |
341 | pub out_dir: Option<&'a Path>, | |
a7813a04 XL |
342 | pub out_file: Option<&'a Path>, |
343 | pub arenas: Option<&'ast ty::CtxtArenas<'ast>>, | |
85aaf69f | 344 | pub expanded_crate: Option<&'a ast::Crate>, |
e9174d1e SL |
345 | pub hir_crate: Option<&'a hir::Crate>, |
346 | pub ast_map: Option<&'a hir_map::Map<'ast>>, | |
a7813a04 | 347 | pub resolutions: Option<&'a Resolutions>, |
b039eaaf | 348 | pub analysis: Option<&'a ty::CrateAnalysis<'a>>, |
a7813a04 | 349 | pub tcx: Option<TyCtxt<'b, 'tcx, 'tcx>>, |
85aaf69f SL |
350 | pub trans: Option<&'a trans::CrateTranslation>, |
351 | } | |
352 | ||
a7813a04 | 353 | impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> { |
85aaf69f | 354 | fn empty(input: &'a Input, |
a7813a04 | 355 | session: &'ast Session, |
c34b1796 | 356 | out_dir: &'a Option<PathBuf>) |
a7813a04 | 357 | -> CompileState<'a, 'b, 'ast, 'tcx> { |
85aaf69f SL |
358 | CompileState { |
359 | input: input, | |
360 | session: session, | |
c34b1796 | 361 | out_dir: out_dir.as_ref().map(|s| &**s), |
a7813a04 XL |
362 | out_file: None, |
363 | arenas: None, | |
85aaf69f | 364 | krate: None, |
9e0c209e | 365 | registry: None, |
a7813a04 | 366 | cstore: None, |
85aaf69f SL |
367 | crate_name: None, |
368 | output_filenames: None, | |
369 | expanded_crate: None, | |
e9174d1e | 370 | hir_crate: None, |
85aaf69f | 371 | ast_map: None, |
a7813a04 | 372 | resolutions: None, |
85aaf69f SL |
373 | analysis: None, |
374 | tcx: None, | |
375 | trans: None, | |
376 | } | |
377 | } | |
378 | ||
379 | fn state_after_parse(input: &'a Input, | |
a7813a04 | 380 | session: &'ast Session, |
c34b1796 | 381 | out_dir: &'a Option<PathBuf>, |
a7813a04 XL |
382 | out_file: &'a Option<PathBuf>, |
383 | krate: ast::Crate, | |
384 | cstore: &'a CStore) | |
385 | -> CompileState<'a, 'b, 'ast, 'tcx> { | |
386 | CompileState { | |
9e0c209e SL |
387 | // Initialize the registry before moving `krate` |
388 | registry: Some(Registry::new(&session, krate.span)), | |
a7813a04 XL |
389 | krate: Some(krate), |
390 | cstore: Some(cstore), | |
391 | out_file: out_file.as_ref().map(|s| &**s), | |
392 | ..CompileState::empty(input, session, out_dir) | |
393 | } | |
85aaf69f SL |
394 | } |
395 | ||
396 | fn state_after_expand(input: &'a Input, | |
a7813a04 | 397 | session: &'ast Session, |
c34b1796 | 398 | out_dir: &'a Option<PathBuf>, |
a7813a04 XL |
399 | out_file: &'a Option<PathBuf>, |
400 | cstore: &'a CStore, | |
85aaf69f SL |
401 | expanded_crate: &'a ast::Crate, |
402 | crate_name: &'a str) | |
a7813a04 | 403 | -> CompileState<'a, 'b, 'ast, 'tcx> { |
85aaf69f SL |
404 | CompileState { |
405 | crate_name: Some(crate_name), | |
a7813a04 | 406 | cstore: Some(cstore), |
85aaf69f | 407 | expanded_crate: Some(expanded_crate), |
a7813a04 | 408 | out_file: out_file.as_ref().map(|s| &**s), |
92a42be0 | 409 | ..CompileState::empty(input, session, out_dir) |
85aaf69f SL |
410 | } |
411 | } | |
412 | ||
a7813a04 XL |
413 | fn state_after_hir_lowering(input: &'a Input, |
414 | session: &'ast Session, | |
415 | out_dir: &'a Option<PathBuf>, | |
416 | out_file: &'a Option<PathBuf>, | |
417 | arenas: &'ast ty::CtxtArenas<'ast>, | |
418 | cstore: &'a CStore, | |
419 | hir_map: &'a hir_map::Map<'ast>, | |
420 | analysis: &'a ty::CrateAnalysis, | |
421 | resolutions: &'a Resolutions, | |
422 | krate: &'a ast::Crate, | |
423 | hir_crate: &'a hir::Crate, | |
424 | crate_name: &'a str) | |
425 | -> CompileState<'a, 'b, 'ast, 'tcx> { | |
85aaf69f SL |
426 | CompileState { |
427 | crate_name: Some(crate_name), | |
a7813a04 XL |
428 | arenas: Some(arenas), |
429 | cstore: Some(cstore), | |
9cc50fc6 | 430 | ast_map: Some(hir_map), |
a7813a04 XL |
431 | analysis: Some(analysis), |
432 | resolutions: Some(resolutions), | |
433 | expanded_crate: Some(krate), | |
e9174d1e | 434 | hir_crate: Some(hir_crate), |
a7813a04 | 435 | out_file: out_file.as_ref().map(|s| &**s), |
92a42be0 | 436 | ..CompileState::empty(input, session, out_dir) |
85aaf69f SL |
437 | } |
438 | } | |
439 | ||
440 | fn state_after_analysis(input: &'a Input, | |
a7813a04 | 441 | session: &'ast Session, |
c34b1796 | 442 | out_dir: &'a Option<PathBuf>, |
a7813a04 | 443 | out_file: &'a Option<PathBuf>, |
9cc50fc6 | 444 | krate: Option<&'a ast::Crate>, |
e9174d1e | 445 | hir_crate: &'a hir::Crate, |
a7813a04 | 446 | analysis: &'a ty::CrateAnalysis<'a>, |
a7813a04 | 447 | tcx: TyCtxt<'b, 'tcx, 'tcx>, |
b039eaaf | 448 | crate_name: &'a str) |
a7813a04 | 449 | -> CompileState<'a, 'b, 'ast, 'tcx> { |
85aaf69f SL |
450 | CompileState { |
451 | analysis: Some(analysis), | |
452 | tcx: Some(tcx), | |
a7813a04 | 453 | expanded_crate: krate, |
e9174d1e | 454 | hir_crate: Some(hir_crate), |
b039eaaf | 455 | crate_name: Some(crate_name), |
a7813a04 | 456 | out_file: out_file.as_ref().map(|s| &**s), |
92a42be0 | 457 | ..CompileState::empty(input, session, out_dir) |
85aaf69f SL |
458 | } |
459 | } | |
460 | ||
461 | ||
462 | fn state_after_llvm(input: &'a Input, | |
a7813a04 | 463 | session: &'ast Session, |
c34b1796 | 464 | out_dir: &'a Option<PathBuf>, |
a7813a04 | 465 | out_file: &'a Option<PathBuf>, |
85aaf69f | 466 | trans: &'a trans::CrateTranslation) |
a7813a04 XL |
467 | -> CompileState<'a, 'b, 'ast, 'tcx> { |
468 | CompileState { | |
469 | trans: Some(trans), | |
470 | out_file: out_file.as_ref().map(|s| &**s), | |
471 | ..CompileState::empty(input, session, out_dir) | |
472 | } | |
85aaf69f | 473 | } |
3157f602 XL |
474 | |
475 | fn state_when_compilation_done(input: &'a Input, | |
476 | session: &'ast Session, | |
477 | out_dir: &'a Option<PathBuf>, | |
478 | out_file: &'a Option<PathBuf>) | |
479 | -> CompileState<'a, 'b, 'ast, 'tcx> { | |
480 | CompileState { | |
481 | out_file: out_file.as_ref().map(|s| &**s), | |
482 | ..CompileState::empty(input, session, out_dir) | |
483 | } | |
484 | } | |
85aaf69f SL |
485 | } |
486 | ||
c30ab7b3 | 487 | pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { |
5bcae85e | 488 | let continue_after_error = sess.opts.debugging_opts.continue_parse_after_error; |
7453a54e | 489 | sess.diagnostic().set_continue_after_error(continue_after_error); |
1a4d82fc | 490 | |
e9174d1e | 491 | let krate = time(sess.time_passes(), "parsing", || { |
1a4d82fc JJ |
492 | match *input { |
493 | Input::File(ref file) => { | |
c30ab7b3 | 494 | parse::parse_crate_from_file(file, &sess.parse_sess) |
1a4d82fc | 495 | } |
54a0048b | 496 | Input::Str { ref input, ref name } => { |
c30ab7b3 | 497 | parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess) |
1a4d82fc JJ |
498 | } |
499 | } | |
54a0048b | 500 | })?; |
1a4d82fc | 501 | |
7453a54e SL |
502 | sess.diagnostic().set_continue_after_error(true); |
503 | ||
1a4d82fc JJ |
504 | if sess.opts.debugging_opts.ast_json_noexpand { |
505 | println!("{}", json::as_json(&krate)); | |
506 | } | |
507 | ||
92a42be0 SL |
508 | if sess.opts.debugging_opts.input_stats { |
509 | println!("Lines of code: {}", sess.codemap().count_lines()); | |
510 | println!("Pre-expansion node count: {}", count_nodes(&krate)); | |
511 | } | |
512 | ||
9cc50fc6 | 513 | if let Some(ref s) = sess.opts.debugging_opts.show_span { |
85aaf69f | 514 | syntax::show_span::run(sess.diagnostic(), s, &krate); |
1a4d82fc JJ |
515 | } |
516 | ||
c30ab7b3 SL |
517 | if sess.opts.debugging_opts.hir_stats { |
518 | hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); | |
519 | } | |
520 | ||
54a0048b | 521 | Ok(krate) |
1a4d82fc JJ |
522 | } |
523 | ||
92a42be0 SL |
524 | fn count_nodes(krate: &ast::Crate) -> usize { |
525 | let mut counter = NodeCounter::new(); | |
526 | visit::walk_crate(&mut counter, krate); | |
527 | counter.count | |
528 | } | |
529 | ||
1a4d82fc JJ |
530 | // For continuing compilation after a parsed crate has been |
531 | // modified | |
532 | ||
3157f602 XL |
533 | pub struct ExpansionResult<'a> { |
534 | pub expanded_crate: ast::Crate, | |
535 | pub defs: hir_map::Definitions, | |
536 | pub analysis: ty::CrateAnalysis<'a>, | |
537 | pub resolutions: Resolutions, | |
538 | pub hir_forest: hir_map::Forest, | |
539 | } | |
540 | ||
1a4d82fc JJ |
541 | /// Run the "early phases" of the compiler: initial `cfg` processing, |
542 | /// loading compiler plugins (including those from `addl_plugins`), | |
543 | /// syntax expansion, secondary `cfg` expansion, synthesis of a test | |
3157f602 XL |
544 | /// harness if one is to be provided, injection of a dependency on the |
545 | /// standard library and prelude, and name resolution. | |
1a4d82fc JJ |
546 | /// |
547 | /// Returns `None` if we're aborting after handling -W help. | |
3157f602 XL |
548 | pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, |
549 | cstore: &CStore, | |
9e0c209e SL |
550 | krate: ast::Crate, |
551 | registry: Option<Registry>, | |
3157f602 XL |
552 | crate_name: &'a str, |
553 | addl_plugins: Option<Vec<String>>, | |
554 | make_glob_map: MakeGlobMap, | |
555 | after_expand: F) | |
556 | -> Result<ExpansionResult<'a>, usize> | |
557 | where F: FnOnce(&ast::Crate) -> CompileResult, | |
558 | { | |
1a4d82fc JJ |
559 | let time_passes = sess.time_passes(); |
560 | ||
9e0c209e SL |
561 | let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test); |
562 | // these need to be set "early" so that expansion sees `quote` if enabled. | |
563 | *sess.features.borrow_mut() = features; | |
9346a6ac | 564 | |
92a42be0 | 565 | *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); |
5bcae85e SL |
566 | *sess.crate_disambiguator.borrow_mut() = |
567 | token::intern(&compute_crate_disambiguator(sess)).as_str(); | |
d9579d0f | 568 | |
e9174d1e | 569 | time(time_passes, "recursion limit", || { |
d9579d0f AL |
570 | middle::recursion_limit::update_recursion_limit(sess, &krate); |
571 | }); | |
572 | ||
92a42be0 | 573 | krate = time(time_passes, "crate injection", || { |
3157f602 XL |
574 | let alt_std_name = sess.opts.alt_std_name.clone(); |
575 | syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) | |
92a42be0 | 576 | }); |
1a4d82fc JJ |
577 | |
578 | let mut addl_plugins = Some(addl_plugins); | |
92a42be0 | 579 | let registrars = time(time_passes, "plugin loading", || { |
54a0048b SL |
580 | plugin::load::load_plugins(sess, |
581 | &cstore, | |
582 | &krate, | |
583 | crate_name, | |
584 | addl_plugins.take().unwrap()) | |
92a42be0 | 585 | }); |
1a4d82fc | 586 | |
9e0c209e | 587 | let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); |
1a4d82fc | 588 | |
e9174d1e | 589 | time(time_passes, "plugin registration", || { |
1a4d82fc JJ |
590 | if sess.features.borrow().rustc_diagnostic_macros { |
591 | registry.register_macro("__diagnostic_used", | |
92a42be0 | 592 | diagnostics::plugin::expand_diagnostic_used); |
1a4d82fc | 593 | registry.register_macro("__register_diagnostic", |
92a42be0 | 594 | diagnostics::plugin::expand_register_diagnostic); |
1a4d82fc | 595 | registry.register_macro("__build_diagnostic_array", |
92a42be0 | 596 | diagnostics::plugin::expand_build_diagnostic_array); |
1a4d82fc JJ |
597 | } |
598 | ||
85aaf69f | 599 | for registrar in registrars { |
1a4d82fc JJ |
600 | registry.args_hidden = Some(registrar.args); |
601 | (registrar.fun)(&mut registry); | |
602 | } | |
603 | }); | |
604 | ||
b039eaaf | 605 | let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, |
7453a54e | 606 | llvm_passes, attributes, mir_passes, .. } = registry; |
1a4d82fc | 607 | |
54a0048b | 608 | sess.track_errors(|| { |
1a4d82fc | 609 | let mut ls = sess.lint_store.borrow_mut(); |
b039eaaf SL |
610 | for pass in early_lint_passes { |
611 | ls.register_early_pass(Some(sess), true, pass); | |
612 | } | |
613 | for pass in late_lint_passes { | |
614 | ls.register_late_pass(Some(sess), true, pass); | |
1a4d82fc JJ |
615 | } |
616 | ||
85aaf69f | 617 | for (name, to) in lint_groups { |
1a4d82fc JJ |
618 | ls.register_group(Some(sess), true, name, to); |
619 | } | |
9346a6ac AL |
620 | |
621 | *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; | |
54a0048b | 622 | sess.mir_passes.borrow_mut().extend(mir_passes); |
62682a34 | 623 | *sess.plugin_attributes.borrow_mut() = attributes.clone(); |
54a0048b | 624 | })?; |
1a4d82fc JJ |
625 | |
626 | // Lint plugins are registered; now we can process command line flags. | |
627 | if sess.opts.describe_lints { | |
7453a54e SL |
628 | super::describe_lints(&sess.lint_store.borrow(), true); |
629 | return Err(0); | |
1a4d82fc | 630 | } |
54a0048b | 631 | sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?; |
1a4d82fc | 632 | |
c30ab7b3 SL |
633 | // Currently, we ignore the name resolution data structures for the purposes of dependency |
634 | // tracking. Instead we will run name resolution and include its output in the hash of each | |
635 | // item, much like we do for macro expansion. In other words, the hash reflects not just | |
636 | // its contents but the results of name resolution on those contents. Hopefully we'll push | |
637 | // this back at some point. | |
638 | let _ignore = sess.dep_graph.in_ignore(); | |
639 | let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); | |
640 | crate_loader.preprocess(&krate); | |
9e0c209e SL |
641 | let resolver_arenas = Resolver::arenas(); |
642 | let mut resolver = | |
643 | Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); | |
c30ab7b3 | 644 | syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); |
9e0c209e | 645 | |
e9174d1e SL |
646 | krate = time(time_passes, "expansion", || { |
647 | // Windows dlls do not have rpaths, so they don't know how to find their | |
648 | // dependencies. It's up to us to tell the system where to find all the | |
649 | // dependent dlls. Note that this uses cfg!(windows) as opposed to | |
650 | // targ_cfg because syntax extensions are always loaded for the host | |
651 | // compiler, not for the target. | |
3157f602 XL |
652 | // |
653 | // This is somewhat of an inherently racy operation, however, as | |
654 | // multiple threads calling this function could possibly continue | |
655 | // extending PATH far beyond what it should. To solve this for now we | |
656 | // just don't add any new elements to PATH which are already there | |
657 | // within PATH. This is basically a targeted fix at #17360 for rustdoc | |
658 | // which runs rustc in parallel but has been seen (#33844) to cause | |
659 | // problems with PATH becoming too long. | |
660 | let mut old_path = OsString::new(); | |
e9174d1e | 661 | if cfg!(windows) { |
3157f602 | 662 | old_path = env::var_os("PATH").unwrap_or(old_path); |
e9174d1e SL |
663 | let mut new_path = sess.host_filesearch(PathKind::All) |
664 | .get_dylib_search_paths(); | |
3157f602 XL |
665 | for path in env::split_paths(&old_path) { |
666 | if !new_path.contains(&path) { | |
667 | new_path.push(path); | |
668 | } | |
669 | } | |
e9174d1e | 670 | env::set_var("PATH", &env::join_paths(new_path).unwrap()); |
1a4d82fc | 671 | } |
e9174d1e SL |
672 | let features = sess.features.borrow(); |
673 | let cfg = syntax::ext::expand::ExpansionConfig { | |
e9174d1e SL |
674 | features: Some(&features), |
675 | recursion_limit: sess.recursion_limit.get(), | |
676 | trace_mac: sess.opts.debugging_opts.trace_macros, | |
3157f602 | 677 | should_test: sess.opts.test, |
9e0c209e | 678 | ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) |
e9174d1e | 679 | }; |
c30ab7b3 SL |
680 | let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); |
681 | let err_count = ecx.parse_sess.span_diagnostic.err_count(); | |
682 | ||
683 | let krate = ecx.monotonic_expander().expand_crate(krate); | |
684 | ||
685 | if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count { | |
686 | ecx.parse_sess.span_diagnostic.abort_if_errors(); | |
687 | } | |
e9174d1e | 688 | if cfg!(windows) { |
3157f602 | 689 | env::set_var("PATH", &old_path); |
e9174d1e | 690 | } |
c30ab7b3 | 691 | krate |
e9174d1e | 692 | }); |
1a4d82fc | 693 | |
9e0c209e SL |
694 | krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); |
695 | ||
92a42be0 | 696 | krate = time(time_passes, "maybe building test harness", || { |
3157f602 | 697 | syntax::test::modify_for_testing(&sess.parse_sess, |
9e0c209e | 698 | &mut resolver, |
3157f602 XL |
699 | sess.opts.test, |
700 | krate, | |
701 | sess.diagnostic()) | |
92a42be0 | 702 | }); |
1a4d82fc | 703 | |
c30ab7b3 SL |
704 | // If we're in rustdoc we're always compiling as an rlib, but that'll trip a |
705 | // bunch of checks in the `modify` function below. For now just skip this | |
706 | // step entirely if we're rustdoc as it's not too useful anyway. | |
707 | if !sess.opts.actually_rustdoc { | |
708 | krate = time(time_passes, "maybe creating a macro crate", || { | |
709 | let crate_types = sess.crate_types.borrow(); | |
710 | let num_crate_types = crate_types.len(); | |
711 | let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); | |
712 | syntax_ext::proc_macro_registrar::modify(&sess.parse_sess, | |
713 | &mut resolver, | |
714 | krate, | |
715 | is_proc_macro_crate, | |
716 | num_crate_types, | |
717 | sess.diagnostic(), | |
718 | &sess.features.borrow()) | |
719 | }); | |
720 | } | |
5bcae85e SL |
721 | |
722 | if sess.opts.debugging_opts.input_stats { | |
723 | println!("Post-expansion node count: {}", count_nodes(&krate)); | |
724 | } | |
725 | ||
c30ab7b3 SL |
726 | if sess.opts.debugging_opts.hir_stats { |
727 | hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); | |
728 | } | |
729 | ||
5bcae85e SL |
730 | if sess.opts.debugging_opts.ast_json { |
731 | println!("{}", json::as_json(&krate)); | |
732 | } | |
733 | ||
92a42be0 SL |
734 | time(time_passes, |
735 | "checking for inline asm in case the target doesn't support it", | |
7453a54e | 736 | || no_asm::check_crate(sess, &krate)); |
1a4d82fc | 737 | |
a7813a04 XL |
738 | // Needs to go *after* expansion to be able to check the results of macro expansion. |
739 | time(time_passes, "complete gated feature checking", || { | |
7453a54e | 740 | sess.track_errors(|| { |
3157f602 XL |
741 | syntax::feature_gate::check_crate(&krate, |
742 | &sess.parse_sess, | |
743 | &sess.features.borrow(), | |
744 | &attributes, | |
745 | sess.opts.unstable_features); | |
7453a54e | 746 | }) |
54a0048b | 747 | })?; |
c34b1796 | 748 | |
3157f602 XL |
749 | time(sess.time_passes(), |
750 | "early lint checks", | |
751 | || lint::check_ast_crate(sess, &krate)); | |
752 | ||
753 | time(sess.time_passes(), | |
754 | "AST validation", | |
755 | || ast_validation::check_crate(sess, &krate)); | |
756 | ||
757 | time(sess.time_passes(), "name resolution", || -> CompileResult { | |
3157f602 XL |
758 | resolver.resolve_imports(); |
759 | ||
760 | // Since import resolution will eventually happen in expansion, | |
761 | // don't perform `after_expand` until after import resolution. | |
762 | after_expand(&krate)?; | |
763 | ||
764 | resolver.resolve_crate(&krate); | |
765 | Ok(()) | |
766 | })?; | |
767 | ||
768 | // Lower ast -> hir. | |
769 | let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { | |
c30ab7b3 SL |
770 | let hir_crate = lower_crate(sess, &krate, &mut resolver); |
771 | ||
772 | if sess.opts.debugging_opts.hir_stats { | |
773 | hir_stats::print_hir_stats(&hir_crate); | |
774 | } | |
775 | ||
776 | hir_map::Forest::new(hir_crate, &sess.dep_graph) | |
3157f602 XL |
777 | }); |
778 | ||
5bcae85e SL |
779 | // Discard hygiene data, which isn't required past lowering to HIR. |
780 | if !keep_hygiene_data(sess) { | |
781 | syntax::ext::hygiene::reset_hygiene_data(); | |
3157f602 XL |
782 | } |
783 | ||
784 | Ok(ExpansionResult { | |
785 | expanded_crate: krate, | |
786 | defs: resolver.definitions, | |
787 | analysis: ty::CrateAnalysis { | |
788 | export_map: resolver.export_map, | |
789 | access_levels: AccessLevels::default(), | |
790 | reachable: NodeSet(), | |
791 | name: crate_name, | |
792 | glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, | |
793 | }, | |
794 | resolutions: Resolutions { | |
795 | def_map: resolver.def_map, | |
796 | freevars: resolver.freevars, | |
797 | trait_map: resolver.trait_map, | |
798 | maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, | |
799 | }, | |
800 | hir_forest: hir_forest | |
801 | }) | |
1a4d82fc JJ |
802 | } |
803 | ||
1a4d82fc JJ |
804 | /// Run the resolution, typechecking, region checking and other |
805 | /// miscellaneous analysis passes on the crate. Return various | |
806 | /// structures carrying the results of the analysis. | |
b039eaaf | 807 | pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, |
9cc50fc6 | 808 | hir_map: hir_map::Map<'tcx>, |
a7813a04 XL |
809 | mut analysis: ty::CrateAnalysis, |
810 | resolutions: Resolutions, | |
62682a34 | 811 | arenas: &'tcx ty::CtxtArenas<'tcx>, |
b039eaaf | 812 | name: &str, |
62682a34 | 813 | f: F) |
7453a54e | 814 | -> Result<R, usize> |
a7813a04 | 815 | where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, |
a7813a04 | 816 | ty::CrateAnalysis, |
9e0c209e | 817 | IncrementalHashesMap, |
a7813a04 | 818 | CompileResult) -> R |
62682a34 | 819 | { |
7453a54e | 820 | macro_rules! try_with_f { |
c30ab7b3 | 821 | ($e: expr, ($t: expr, $a: expr, $h: expr)) => { |
7453a54e SL |
822 | match $e { |
823 | Ok(x) => x, | |
824 | Err(x) => { | |
c30ab7b3 | 825 | f($t, $a, $h, Err(x)); |
7453a54e SL |
826 | return Err(x); |
827 | } | |
828 | } | |
829 | } | |
830 | } | |
831 | ||
1a4d82fc | 832 | let time_passes = sess.time_passes(); |
1a4d82fc | 833 | |
54a0048b | 834 | let lang_items = time(time_passes, "language item collection", || { |
7453a54e SL |
835 | sess.track_errors(|| { |
836 | middle::lang_items::collect_language_items(&sess, &hir_map) | |
837 | }) | |
54a0048b | 838 | })?; |
1a4d82fc | 839 | |
54a0048b SL |
840 | let named_region_map = time(time_passes, |
841 | "lifetime resolution", | |
842 | || middle::resolve_lifetime::krate(sess, | |
843 | &hir_map, | |
3157f602 | 844 | &resolutions.def_map))?; |
1a4d82fc | 845 | |
92a42be0 SL |
846 | time(time_passes, |
847 | "looking for entry point", | |
9cc50fc6 | 848 | || middle::entry::find_entry_point(sess, &hir_map)); |
1a4d82fc | 849 | |
92a42be0 | 850 | sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { |
7453a54e | 851 | plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) |
92a42be0 | 852 | })); |
9e0c209e | 853 | sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); |
1a4d82fc | 854 | |
92a42be0 SL |
855 | let region_map = time(time_passes, |
856 | "region resolution", | |
7453a54e | 857 | || middle::region::resolve_crate(sess, &hir_map)); |
1a4d82fc | 858 | |
92a42be0 SL |
859 | time(time_passes, |
860 | "loop checking", | |
7453a54e | 861 | || loops::check_crate(sess, &hir_map)); |
1a4d82fc | 862 | |
54a0048b | 863 | time(time_passes, |
7453a54e | 864 | "static item recursion checking", |
3157f602 | 865 | || static_recursion::check_crate(sess, &resolutions.def_map, &hir_map))?; |
7453a54e SL |
866 | |
867 | let index = stability::Index::new(&hir_map); | |
1a4d82fc | 868 | |
54a0048b | 869 | TyCtxt::create_and_enter(sess, |
a7813a04 XL |
870 | arenas, |
871 | resolutions.def_map, | |
5bcae85e | 872 | resolutions.trait_map, |
a7813a04 XL |
873 | named_region_map, |
874 | hir_map, | |
875 | resolutions.freevars, | |
876 | resolutions.maybe_unused_trait_imports, | |
877 | region_map, | |
878 | lang_items, | |
879 | index, | |
880 | name, | |
881 | |tcx| { | |
9e0c209e SL |
882 | let incremental_hashes_map = |
883 | time(time_passes, | |
884 | "compute_incremental_hashes_map", | |
885 | || rustc_incremental::compute_incremental_hashes_map(tcx)); | |
54a0048b SL |
886 | time(time_passes, |
887 | "load_dep_graph", | |
9e0c209e | 888 | || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map)); |
54a0048b | 889 | |
7453a54e | 890 | // passes are timed inside typeck |
c30ab7b3 | 891 | try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map)); |
7453a54e SL |
892 | |
893 | time(time_passes, | |
894 | "const checking", | |
895 | || consts::check_crate(tcx)); | |
896 | ||
897 | analysis.access_levels = | |
898 | time(time_passes, "privacy checking", || { | |
54a0048b | 899 | rustc_privacy::check_crate(tcx, &analysis.export_map) |
7453a54e SL |
900 | }); |
901 | ||
902 | // Do not move this check past lint | |
903 | time(time_passes, "stability index", || { | |
904 | tcx.stability.borrow_mut().build(tcx, &analysis.access_levels) | |
905 | }); | |
906 | ||
907 | time(time_passes, | |
908 | "intrinsic checking", | |
909 | || middle::intrinsicck::check_crate(tcx)); | |
910 | ||
911 | time(time_passes, | |
912 | "effect checking", | |
913 | || middle::effect::check_crate(tcx)); | |
914 | ||
915 | time(time_passes, | |
916 | "match checking", | |
54a0048b | 917 | || check_match::check_crate(tcx)); |
7453a54e SL |
918 | |
919 | // this must run before MIR dump, because | |
920 | // "not all control paths return a value" is reported here. | |
921 | // | |
922 | // maybe move the check to a MIR pass? | |
923 | time(time_passes, | |
924 | "liveness checking", | |
925 | || middle::liveness::check_crate(tcx)); | |
926 | ||
927 | time(time_passes, | |
928 | "rvalue checking", | |
929 | || rvalues::check_crate(tcx)); | |
930 | ||
c30ab7b3 SL |
931 | time(time_passes, |
932 | "MIR dump", | |
933 | || mir::mir_map::build_mir_for_crate(tcx)); | |
7453a54e | 934 | |
c30ab7b3 | 935 | time(time_passes, "MIR cleanup and validation", || { |
54a0048b | 936 | let mut passes = sess.mir_passes.borrow_mut(); |
c30ab7b3 SL |
937 | // Push all the built-in validation passes. |
938 | // NB: if you’re adding an *optimisation* it ought to go to another set of passes | |
939 | // in stage 4 below. | |
3157f602 | 940 | passes.push_hook(box mir::transform::dump_mir::DumpMir); |
c30ab7b3 SL |
941 | passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); |
942 | passes.push_pass( | |
943 | box mir::transform::qualify_consts::QualifyAndPromoteConstants::default()); | |
54a0048b | 944 | passes.push_pass(box mir::transform::type_check::TypeckMir); |
3157f602 XL |
945 | passes.push_pass( |
946 | box mir::transform::simplify_branches::SimplifyBranches::new("initial")); | |
c30ab7b3 | 947 | passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); |
54a0048b | 948 | // And run everything. |
c30ab7b3 | 949 | passes.run_passes(tcx); |
54a0048b | 950 | }); |
7453a54e SL |
951 | |
952 | time(time_passes, | |
953 | "borrow checking", | |
c30ab7b3 | 954 | || borrowck::check_crate(tcx)); |
7453a54e SL |
955 | |
956 | // Avoid overwhelming user with errors if type checking failed. | |
957 | // I'm not sure how helpful this is, to be honest, but it avoids | |
958 | // a | |
959 | // lot of annoying errors in the compile-fail tests (basically, | |
960 | // lint warnings and so on -- kindck used to do this abort, but | |
961 | // kindck is gone now). -nmatsakis | |
962 | if sess.err_count() > 0 { | |
c30ab7b3 | 963 | return Ok(f(tcx, analysis, incremental_hashes_map, Err(sess.err_count()))); |
7453a54e SL |
964 | } |
965 | ||
966 | analysis.reachable = | |
967 | time(time_passes, | |
968 | "reachability checking", | |
969 | || reachable::find_reachable(tcx, &analysis.access_levels)); | |
970 | ||
971 | time(time_passes, "death checking", || { | |
972 | middle::dead::check_crate(tcx, &analysis.access_levels); | |
973 | }); | |
974 | ||
975 | let ref lib_features_used = | |
976 | time(time_passes, | |
977 | "stability checking", | |
978 | || stability::check_unstable_api_usage(tcx)); | |
979 | ||
980 | time(time_passes, "unused lib feature checking", || { | |
981 | stability::check_unused_or_stable_features(&tcx.sess, | |
982 | lib_features_used) | |
983 | }); | |
984 | ||
985 | time(time_passes, | |
986 | "lint checking", | |
987 | || lint::check_crate(tcx, &analysis.access_levels)); | |
988 | ||
989 | // The above three passes generate errors w/o aborting | |
990 | if sess.err_count() > 0 { | |
c30ab7b3 | 991 | return Ok(f(tcx, analysis, incremental_hashes_map, Err(sess.err_count()))); |
7453a54e SL |
992 | } |
993 | ||
c30ab7b3 | 994 | Ok(f(tcx, analysis, incremental_hashes_map, Ok(()))) |
7453a54e | 995 | }) |
1a4d82fc JJ |
996 | } |
997 | ||
1a4d82fc | 998 | /// Run the translation phase to LLVM, after which the AST and analysis can |
a7813a04 | 999 | pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
9e0c209e SL |
1000 | analysis: ty::CrateAnalysis, |
1001 | incremental_hashes_map: &IncrementalHashesMap) | |
a7813a04 | 1002 | -> trans::CrateTranslation { |
62682a34 | 1003 | let time_passes = tcx.sess.time_passes(); |
1a4d82fc | 1004 | |
92a42be0 SL |
1005 | time(time_passes, |
1006 | "resolving dependency formats", | |
1007 | || dependency_format::calculate(&tcx.sess)); | |
1008 | ||
c30ab7b3 SL |
1009 | // Run the passes that transform the MIR into a more suitable form for translation to LLVM |
1010 | // code. | |
1011 | time(time_passes, "MIR optimisations", || { | |
54a0048b | 1012 | let mut passes = ::rustc::mir::transform::Passes::new(); |
3157f602 | 1013 | passes.push_hook(box mir::transform::dump_mir::DumpMir); |
54a0048b | 1014 | passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); |
c30ab7b3 | 1015 | passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); |
3157f602 | 1016 | |
9e0c209e | 1017 | // From here on out, regions are gone. |
54a0048b | 1018 | passes.push_pass(box mir::transform::erase_regions::EraseRegions); |
3157f602 XL |
1019 | |
1020 | passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); | |
1021 | passes.push_pass(box borrowck::ElaborateDrops); | |
1022 | passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); | |
c30ab7b3 | 1023 | passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); |
3157f602 | 1024 | |
9e0c209e SL |
1025 | // No lifetime analysis based on borrowing can be done from here on out. |
1026 | passes.push_pass(box mir::transform::instcombine::InstCombine::new()); | |
5bcae85e | 1027 | passes.push_pass(box mir::transform::deaggregator::Deaggregator); |
9e0c209e | 1028 | passes.push_pass(box mir::transform::copy_prop::CopyPropagation); |
5bcae85e | 1029 | |
c30ab7b3 | 1030 | passes.push_pass(box mir::transform::simplify::SimplifyLocals); |
3157f602 XL |
1031 | passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); |
1032 | passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); | |
1033 | ||
c30ab7b3 | 1034 | passes.run_passes(tcx); |
54a0048b SL |
1035 | }); |
1036 | ||
1037 | let translation = | |
1038 | time(time_passes, | |
1039 | "translation", | |
c30ab7b3 | 1040 | move || trans::trans_crate(tcx, analysis, &incremental_hashes_map)); |
54a0048b | 1041 | |
92a42be0 | 1042 | time(time_passes, |
54a0048b | 1043 | "assert dep graph", |
9e0c209e | 1044 | || rustc_incremental::assert_dep_graph(tcx)); |
1a4d82fc | 1045 | |
92a42be0 | 1046 | time(time_passes, |
54a0048b | 1047 | "serialize dep graph", |
9e0c209e SL |
1048 | || rustc_incremental::save_dep_graph(tcx, |
1049 | &incremental_hashes_map, | |
1050 | translation.link.crate_hash)); | |
54a0048b | 1051 | translation |
1a4d82fc JJ |
1052 | } |
1053 | ||
1054 | /// Run LLVM itself, producing a bitcode file, assembly file or object file | |
1055 | /// as a side effect. | |
1056 | pub fn phase_5_run_llvm_passes(sess: &Session, | |
1057 | trans: &trans::CrateTranslation, | |
7453a54e | 1058 | outputs: &OutputFilenames) -> CompileResult { |
1a4d82fc | 1059 | if sess.opts.cg.no_integrated_as { |
5bcae85e | 1060 | let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]); |
92a42be0 SL |
1061 | time(sess.time_passes(), |
1062 | "LLVM passes", | |
5bcae85e | 1063 | || write::run_passes(sess, trans, &output_types, outputs)); |
1a4d82fc JJ |
1064 | |
1065 | write::run_assembler(sess, outputs); | |
1066 | ||
1067 | // Remove assembly source, unless --save-temps was specified | |
1068 | if !sess.opts.cg.save_temps { | |
5bcae85e | 1069 | fs::remove_file(&outputs.temp_path(OutputType::Assembly, None)).unwrap(); |
1a4d82fc JJ |
1070 | } |
1071 | } else { | |
92a42be0 SL |
1072 | time(sess.time_passes(), |
1073 | "LLVM passes", | |
1074 | || write::run_passes(sess, trans, &sess.opts.output_types, outputs)); | |
1a4d82fc JJ |
1075 | } |
1076 | ||
5bcae85e SL |
1077 | time(sess.time_passes(), |
1078 | "serialize work products", | |
9e0c209e | 1079 | move || rustc_incremental::save_work_products(sess)); |
5bcae85e | 1080 | |
7453a54e SL |
1081 | if sess.err_count() > 0 { |
1082 | Err(sess.err_count()) | |
1083 | } else { | |
1084 | Ok(()) | |
1085 | } | |
1a4d82fc JJ |
1086 | } |
1087 | ||
1088 | /// Run the linker on any artifacts that resulted from the LLVM run. | |
1089 | /// This should produce either a finished executable or library. | |
1090 | pub fn phase_6_link_output(sess: &Session, | |
1091 | trans: &trans::CrateTranslation, | |
1092 | outputs: &OutputFilenames) { | |
92a42be0 SL |
1093 | time(sess.time_passes(), |
1094 | "linking", | |
1095 | || link::link_binary(sess, trans, outputs, &trans.link.crate_name)); | |
1a4d82fc JJ |
1096 | } |
1097 | ||
1098 | fn escape_dep_filename(filename: &str) -> String { | |
1099 | // Apparently clang and gcc *only* escape spaces: | |
1100 | // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4 | |
1101 | filename.replace(" ", "\\ ") | |
1102 | } | |
1103 | ||
5bcae85e | 1104 | fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) { |
1a4d82fc | 1105 | let mut out_filenames = Vec::new(); |
b039eaaf | 1106 | for output_type in sess.opts.output_types.keys() { |
1a4d82fc JJ |
1107 | let file = outputs.path(*output_type); |
1108 | match *output_type { | |
b039eaaf | 1109 | OutputType::Exe => { |
62682a34 | 1110 | for output in sess.crate_types.borrow().iter() { |
5bcae85e | 1111 | let p = link::filename_for_input(sess, *output, crate_name, outputs); |
1a4d82fc JJ |
1112 | out_filenames.push(p); |
1113 | } | |
1114 | } | |
92a42be0 SL |
1115 | _ => { |
1116 | out_filenames.push(file); | |
1117 | } | |
1a4d82fc JJ |
1118 | } |
1119 | } | |
1120 | ||
b039eaaf SL |
1121 | // Write out dependency rules to the dep-info file if requested |
1122 | if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { | |
92a42be0 | 1123 | return; |
b039eaaf SL |
1124 | } |
1125 | let deps_filename = outputs.path(OutputType::DepInfo); | |
1a4d82fc | 1126 | |
92a42be0 SL |
1127 | let result = |
1128 | (|| -> io::Result<()> { | |
1129 | // Build a list of files used to compile the output and | |
1130 | // write Makefile-compatible dependency rules | |
1131 | let files: Vec<String> = sess.codemap() | |
1132 | .files | |
1133 | .borrow() | |
1134 | .iter() | |
1135 | .filter(|fmap| fmap.is_real_file()) | |
1136 | .filter(|fmap| !fmap.is_imported()) | |
1137 | .map(|fmap| escape_dep_filename(&fmap.name)) | |
1138 | .collect(); | |
54a0048b | 1139 | let mut file = fs::File::create(&deps_filename)?; |
92a42be0 | 1140 | for path in &out_filenames { |
54a0048b | 1141 | write!(file, "{}: {}\n\n", path.display(), files.join(" "))?; |
92a42be0 | 1142 | } |
b039eaaf | 1143 | |
92a42be0 SL |
1144 | // Emit a fake target for each input file to the compilation. This |
1145 | // prevents `make` from spitting out an error if a file is later | |
1146 | // deleted. For more info see #28735 | |
1147 | for path in files { | |
54a0048b | 1148 | writeln!(file, "{}:", path)?; |
92a42be0 SL |
1149 | } |
1150 | Ok(()) | |
1151 | })(); | |
1a4d82fc JJ |
1152 | |
1153 | match result { | |
1154 | Ok(()) => {} | |
1155 | Err(e) => { | |
1156 | sess.fatal(&format!("error writing dependencies to `{}`: {}", | |
92a42be0 SL |
1157 | deps_filename.display(), |
1158 | e)); | |
1a4d82fc JJ |
1159 | } |
1160 | } | |
1161 | } | |
1162 | ||
92a42be0 | 1163 | pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> { |
1a4d82fc | 1164 | // Unconditionally collect crate types from attributes to make them used |
92a42be0 SL |
1165 | let attr_types: Vec<config::CrateType> = |
1166 | attrs.iter() | |
1167 | .filter_map(|a| { | |
1168 | if a.check_name("crate_type") { | |
1169 | match a.value_str() { | |
1170 | Some(ref n) if *n == "rlib" => { | |
1171 | Some(config::CrateTypeRlib) | |
1172 | } | |
1173 | Some(ref n) if *n == "dylib" => { | |
1174 | Some(config::CrateTypeDylib) | |
1175 | } | |
a7813a04 XL |
1176 | Some(ref n) if *n == "cdylib" => { |
1177 | Some(config::CrateTypeCdylib) | |
1178 | } | |
92a42be0 SL |
1179 | Some(ref n) if *n == "lib" => { |
1180 | Some(config::default_lib_output()) | |
1181 | } | |
1182 | Some(ref n) if *n == "staticlib" => { | |
1183 | Some(config::CrateTypeStaticlib) | |
1184 | } | |
c30ab7b3 SL |
1185 | Some(ref n) if *n == "proc-macro" => { |
1186 | Some(config::CrateTypeProcMacro) | |
9e0c209e | 1187 | } |
92a42be0 SL |
1188 | Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), |
1189 | Some(_) => { | |
1190 | session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES, | |
1191 | ast::CRATE_NODE_ID, | |
1192 | a.span, | |
1193 | "invalid `crate_type` value".to_string()); | |
1194 | None | |
1195 | } | |
1196 | _ => { | |
9cc50fc6 SL |
1197 | session.struct_span_err(a.span, "`crate_type` requires a value") |
1198 | .note("for example: `#![crate_type=\"lib\"]`") | |
1199 | .emit(); | |
92a42be0 SL |
1200 | None |
1201 | } | |
1202 | } | |
1203 | } else { | |
1204 | None | |
1205 | } | |
1206 | }) | |
1207 | .collect(); | |
1a4d82fc JJ |
1208 | |
1209 | // If we're generating a test executable, then ignore all other output | |
1210 | // styles at all other locations | |
1211 | if session.opts.test { | |
92a42be0 | 1212 | return vec![config::CrateTypeExecutable]; |
1a4d82fc JJ |
1213 | } |
1214 | ||
1215 | // Only check command line flags if present. If no types are specified by | |
1216 | // command line, then reuse the empty `base` Vec to hold the types that | |
1217 | // will be found in crate attributes. | |
1218 | let mut base = session.opts.crate_types.clone(); | |
9346a6ac | 1219 | if base.is_empty() { |
62682a34 | 1220 | base.extend(attr_types); |
9346a6ac | 1221 | if base.is_empty() { |
1a4d82fc JJ |
1222 | base.push(link::default_output_for_target(session)); |
1223 | } | |
1224 | base.sort(); | |
1225 | base.dedup(); | |
1226 | } | |
1227 | ||
92a42be0 SL |
1228 | base.into_iter() |
1229 | .filter(|crate_type| { | |
1230 | let res = !link::invalid_output_for_target(session, *crate_type); | |
1a4d82fc | 1231 | |
92a42be0 SL |
1232 | if !res { |
1233 | session.warn(&format!("dropping unsupported crate type `{}` for target `{}`", | |
1234 | *crate_type, | |
1235 | session.opts.target_triple)); | |
1236 | } | |
1a4d82fc | 1237 | |
92a42be0 SL |
1238 | res |
1239 | }) | |
1240 | .collect() | |
1a4d82fc JJ |
1241 | } |
1242 | ||
54a0048b | 1243 | pub fn compute_crate_disambiguator(session: &Session) -> String { |
c30ab7b3 SL |
1244 | use std::hash::Hasher; |
1245 | ||
1246 | // The crate_disambiguator is a 128 bit hash. The disambiguator is fed | |
1247 | // into various other hashes quite a bit (symbol hashes, incr. comp. hashes, | |
1248 | // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits | |
1249 | // should still be safe enough to avoid collisions in practice. | |
1250 | // FIXME(mw): It seems that the crate_disambiguator is used everywhere as | |
1251 | // a hex-string instead of raw bytes. We should really use the | |
1252 | // smaller representation. | |
1253 | let mut hasher = ArchIndependentHasher::new(Blake2bHasher::new(128 / 8, &[])); | |
54a0048b SL |
1254 | |
1255 | let mut metadata = session.opts.cg.metadata.clone(); | |
1256 | // We don't want the crate_disambiguator to dependent on the order | |
1257 | // -C metadata arguments, so sort them: | |
1258 | metadata.sort(); | |
1259 | // Every distinct -C metadata value is only incorporated once: | |
1260 | metadata.dedup(); | |
1261 | ||
c30ab7b3 | 1262 | hasher.write(b"metadata"); |
54a0048b SL |
1263 | for s in &metadata { |
1264 | // Also incorporate the length of a metadata string, so that we generate | |
1265 | // different values for `-Cmetadata=ab -Cmetadata=c` and | |
1266 | // `-Cmetadata=a -Cmetadata=bc` | |
c30ab7b3 SL |
1267 | hasher.write_usize(s.len()); |
1268 | hasher.write(s.as_bytes()); | |
54a0048b SL |
1269 | } |
1270 | ||
c30ab7b3 SL |
1271 | let mut hash_state = hasher.into_inner(); |
1272 | let hash_bytes = hash_state.finalize(); | |
54a0048b SL |
1273 | |
1274 | // If this is an executable, add a special suffix, so that we don't get | |
1275 | // symbol conflicts when linking against a library of the same name. | |
c30ab7b3 | 1276 | let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable); |
54a0048b | 1277 | |
c30ab7b3 | 1278 | format!("{:x}{}", FmtWrap(hash_bytes), if is_exe { "-exe" } else {""}) |
1a4d82fc JJ |
1279 | } |
1280 | ||
1281 | pub fn build_output_filenames(input: &Input, | |
c34b1796 AL |
1282 | odir: &Option<PathBuf>, |
1283 | ofile: &Option<PathBuf>, | |
1a4d82fc JJ |
1284 | attrs: &[ast::Attribute], |
1285 | sess: &Session) | |
92a42be0 | 1286 | -> OutputFilenames { |
1a4d82fc JJ |
1287 | match *ofile { |
1288 | None => { | |
1289 | // "-" as input file will cause the parser to read from stdin so we | |
1290 | // have to make up a name | |
1291 | // We want to toss everything after the final '.' | |
1292 | let dirpath = match *odir { | |
1293 | Some(ref d) => d.clone(), | |
92a42be0 | 1294 | None => PathBuf::new(), |
1a4d82fc JJ |
1295 | }; |
1296 | ||
1297 | // If a crate name is present, we use it as the link name | |
92a42be0 SL |
1298 | let stem = sess.opts |
1299 | .crate_name | |
1300 | .clone() | |
1301 | .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string())) | |
1302 | .unwrap_or(input.filestem()); | |
1a4d82fc JJ |
1303 | |
1304 | OutputFilenames { | |
1305 | out_directory: dirpath, | |
1306 | out_filestem: stem, | |
1307 | single_output_file: None, | |
1308 | extra: sess.opts.cg.extra_filename.clone(), | |
b039eaaf | 1309 | outputs: sess.opts.output_types.clone(), |
1a4d82fc JJ |
1310 | } |
1311 | } | |
1312 | ||
1313 | Some(ref out_file) => { | |
92a42be0 SL |
1314 | let unnamed_output_types = sess.opts |
1315 | .output_types | |
1316 | .values() | |
b039eaaf SL |
1317 | .filter(|a| a.is_none()) |
1318 | .count(); | |
1319 | let ofile = if unnamed_output_types > 1 { | |
92a42be0 SL |
1320 | sess.warn("ignoring specified output filename because multiple outputs were \ |
1321 | requested"); | |
1a4d82fc JJ |
1322 | None |
1323 | } else { | |
1324 | Some(out_file.clone()) | |
1325 | }; | |
1326 | if *odir != None { | |
1327 | sess.warn("ignoring --out-dir flag due to -o flag."); | |
1328 | } | |
c34b1796 AL |
1329 | |
1330 | let cur_dir = Path::new(""); | |
1331 | ||
1a4d82fc | 1332 | OutputFilenames { |
c34b1796 | 1333 | out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(), |
92a42be0 SL |
1334 | out_filestem: out_file.file_stem() |
1335 | .unwrap_or(OsStr::new("")) | |
1336 | .to_str() | |
1337 | .unwrap() | |
1338 | .to_string(), | |
1a4d82fc JJ |
1339 | single_output_file: ofile, |
1340 | extra: sess.opts.cg.extra_filename.clone(), | |
b039eaaf | 1341 | outputs: sess.opts.output_types.clone(), |
1a4d82fc JJ |
1342 | } |
1343 | } | |
1344 | } | |
1345 | } | |
5bcae85e SL |
1346 | |
1347 | // For use by the `rusti` project (https://github.com/murarth/rusti). | |
1348 | pub fn reset_thread_local_state() { | |
1349 | // These may be left in an incoherent state after a previous compile. | |
1350 | syntax::ext::hygiene::reset_hygiene_data(); | |
1351 | // `clear_ident_interner` can be used to free memory, but it does not restore the initial state. | |
1352 | token::reset_ident_interner(); | |
1353 | } |