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