]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2014-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 | ||
11 | //! The Rust compiler. | |
12 | //! | |
13 | //! # Note | |
14 | //! | |
15 | //! This API is completely unstable and subject to change. | |
16 | ||
17 | #![crate_name = "rustc_driver"] | |
e9174d1e | 18 | #![unstable(feature = "rustc_private", issue = "27812")] |
1a4d82fc JJ |
19 | #![crate_type = "dylib"] |
20 | #![crate_type = "rlib"] | |
e9174d1e | 21 | #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", |
62682a34 | 22 | html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
e9174d1e | 23 | html_root_url = "https://doc.rust-lang.org/nightly/")] |
32a655c1 | 24 | #![deny(warnings)] |
1a4d82fc | 25 | |
1a4d82fc | 26 | #![feature(box_syntax)] |
8bb4bdeb | 27 | #![feature(loop_break_value)] |
85aaf69f | 28 | #![feature(libc)] |
85aaf69f | 29 | #![feature(quote)] |
1a4d82fc | 30 | #![feature(rustc_diagnostic_macros)] |
85aaf69f | 31 | #![feature(rustc_private)] |
c34b1796 | 32 | #![feature(set_stdio)] |
62682a34 | 33 | #![feature(staged_api)] |
1a4d82fc JJ |
34 | |
35 | extern crate arena; | |
1a4d82fc JJ |
36 | extern crate getopts; |
37 | extern crate graphviz; | |
38 | extern crate libc; | |
39 | extern crate rustc; | |
40 | extern crate rustc_back; | |
41 | extern crate rustc_borrowck; | |
54a0048b | 42 | extern crate rustc_const_eval; |
c30ab7b3 | 43 | extern crate rustc_data_structures; |
3157f602 | 44 | extern crate rustc_errors as errors; |
9cc50fc6 | 45 | extern crate rustc_passes; |
c34b1796 | 46 | extern crate rustc_lint; |
92a42be0 | 47 | extern crate rustc_plugin; |
85aaf69f | 48 | extern crate rustc_privacy; |
54a0048b | 49 | extern crate rustc_incremental; |
92a42be0 | 50 | extern crate rustc_metadata; |
e9174d1e | 51 | extern crate rustc_mir; |
1a4d82fc | 52 | extern crate rustc_resolve; |
54a0048b | 53 | extern crate rustc_save_analysis; |
1a4d82fc JJ |
54 | extern crate rustc_trans; |
55 | extern crate rustc_typeck; | |
56 | extern crate serialize; | |
c34b1796 | 57 | extern crate rustc_llvm as llvm; |
92a42be0 SL |
58 | #[macro_use] |
59 | extern crate log; | |
92a42be0 | 60 | extern crate syntax; |
9cc50fc6 | 61 | extern crate syntax_ext; |
3157f602 | 62 | extern crate syntax_pos; |
1a4d82fc | 63 | |
85aaf69f SL |
64 | use driver::CompileController; |
65 | use pretty::{PpMode, UserIdentifiedItem}; | |
66 | ||
67 | use rustc_resolve as resolve; | |
54a0048b | 68 | use rustc_save_analysis as save; |
1a4d82fc | 69 | use rustc_trans::back::link; |
5bcae85e | 70 | use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS}; |
a7813a04 XL |
71 | use rustc::dep_graph::DepGraph; |
72 | use rustc::session::{self, config, Session, build_session, CompileResult}; | |
9cc50fc6 | 73 | use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; |
9e0c209e | 74 | use rustc::session::config::nightly_options; |
476ff2be | 75 | use rustc::session::{early_error, early_warn}; |
1a4d82fc JJ |
76 | use rustc::lint::Lint; |
77 | use rustc::lint; | |
c30ab7b3 | 78 | use rustc_metadata::locator; |
92a42be0 | 79 | use rustc_metadata::cstore::CStore; |
85aaf69f | 80 | use rustc::util::common::time; |
1a4d82fc | 81 | |
476ff2be SL |
82 | use serialize::json::ToJson; |
83 | ||
32a655c1 | 84 | use std::any::Any; |
9cc50fc6 | 85 | use std::cmp::max; |
1a4d82fc | 86 | use std::cmp::Ordering::Equal; |
9cc50fc6 | 87 | use std::default::Default; |
85aaf69f | 88 | use std::env; |
c34b1796 AL |
89 | use std::io::{self, Read, Write}; |
90 | use std::iter::repeat; | |
91 | use std::path::PathBuf; | |
62682a34 | 92 | use std::process; |
92a42be0 | 93 | use std::rc::Rc; |
c34b1796 AL |
94 | use std::str; |
95 | use std::sync::{Arc, Mutex}; | |
1a4d82fc JJ |
96 | use std::thread; |
97 | ||
476ff2be | 98 | use syntax::ast; |
3157f602 | 99 | use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; |
54a0048b | 100 | use syntax::feature_gate::{GatedCfg, UnstableFeatures}; |
5bcae85e | 101 | use syntax::parse::{self, PResult}; |
476ff2be | 102 | use syntax_pos::{DUMMY_SP, MultiSpan}; |
1a4d82fc JJ |
103 | |
104 | #[cfg(test)] | |
105 | pub mod test; | |
106 | ||
107 | pub mod driver; | |
108 | pub mod pretty; | |
e9174d1e | 109 | pub mod target_features; |
9e0c209e | 110 | mod derive_registrar; |
85aaf69f | 111 | |
92a42be0 SL |
112 | const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ |
113 | md#bug-reports"; | |
114 | ||
7453a54e SL |
115 | #[inline] |
116 | fn abort_msg(err_count: usize) -> String { | |
117 | match err_count { | |
118 | 0 => "aborting with no errors (maybe a bug?)".to_owned(), | |
119 | 1 => "aborting due to previous error".to_owned(), | |
120 | e => format!("aborting due to {} previous errors", e), | |
121 | } | |
122 | } | |
123 | ||
124 | pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T { | |
125 | match result { | |
126 | Err(err_count) => { | |
127 | sess.fatal(&abort_msg(err_count)); | |
128 | } | |
129 | Ok(x) => x, | |
130 | } | |
131 | } | |
132 | ||
c30ab7b3 SL |
133 | pub fn run<F>(run_compiler: F) -> isize |
134 | where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static | |
135 | { | |
7453a54e | 136 | monitor(move || { |
c30ab7b3 | 137 | let (result, session) = run_compiler(); |
7453a54e SL |
138 | if let Err(err_count) = result { |
139 | if err_count > 0 { | |
140 | match session { | |
141 | Some(sess) => sess.fatal(&abort_msg(err_count)), | |
142 | None => { | |
5bcae85e | 143 | let emitter = |
c30ab7b3 | 144 | errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None); |
5bcae85e SL |
145 | let handler = errors::Handler::with_emitter(true, false, Box::new(emitter)); |
146 | handler.emit(&MultiSpan::new(), | |
147 | &abort_msg(err_count), | |
148 | errors::Level::Fatal); | |
7453a54e SL |
149 | exit_on_err(); |
150 | } | |
151 | } | |
152 | } | |
153 | } | |
154 | }); | |
1a4d82fc JJ |
155 | 0 |
156 | } | |
157 | ||
a7813a04 XL |
158 | // Parse args and run the compiler. This is the primary entry point for rustc. |
159 | // See comments on CompilerCalls below for details about the callbacks argument. | |
160 | // The FileLoader provides a way to load files from sources other than the file system. | |
c30ab7b3 SL |
161 | pub fn run_compiler<'a>(args: &[String], |
162 | callbacks: &mut CompilerCalls<'a>, | |
163 | file_loader: Option<Box<FileLoader + 'static>>, | |
164 | emitter_dest: Option<Box<Write + Send>>) | |
165 | -> (CompileResult, Option<Session>) | |
166 | { | |
7453a54e | 167 | macro_rules! do_or_return {($expr: expr, $sess: expr) => { |
85aaf69f | 168 | match $expr { |
7453a54e | 169 | Compilation::Stop => return (Ok(()), $sess), |
85aaf69f SL |
170 | Compilation::Continue => {} |
171 | } | |
172 | }} | |
1a4d82fc | 173 | |
54a0048b | 174 | let matches = match handle_options(args) { |
1a4d82fc | 175 | Some(matches) => matches, |
7453a54e | 176 | None => return (Ok(()), None), |
1a4d82fc JJ |
177 | }; |
178 | ||
5bcae85e | 179 | let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); |
85aaf69f | 180 | |
54a0048b | 181 | if sopts.debugging_opts.debug_llvm { |
5bcae85e | 182 | unsafe { llvm::LLVMRustSetDebug(1); } |
54a0048b SL |
183 | } |
184 | ||
e9174d1e | 185 | let descriptions = diagnostics_registry(); |
85aaf69f | 186 | |
7453a54e SL |
187 | do_or_return!(callbacks.early_callback(&matches, |
188 | &sopts, | |
5bcae85e | 189 | &cfg, |
7453a54e SL |
190 | &descriptions, |
191 | sopts.error_format), | |
192 | None); | |
85aaf69f SL |
193 | |
194 | let (odir, ofile) = make_output(&matches); | |
c34b1796 | 195 | let (input, input_file_path) = match make_input(&matches.free) { |
85aaf69f | 196 | Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), |
5bcae85e | 197 | None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { |
85aaf69f | 198 | Some((input, input_file_path)) => (input, input_file_path), |
7453a54e | 199 | None => return (Ok(()), None), |
92a42be0 | 200 | }, |
85aaf69f SL |
201 | }; |
202 | ||
a7813a04 | 203 | let dep_graph = DepGraph::new(sopts.build_dep_graph()); |
5bcae85e | 204 | let cstore = Rc::new(CStore::new(&dep_graph)); |
c30ab7b3 SL |
205 | |
206 | let loader = file_loader.unwrap_or(box RealFileLoader); | |
a7813a04 | 207 | let codemap = Rc::new(CodeMap::with_file_loader(loader)); |
c30ab7b3 SL |
208 | let mut sess = session::build_session_with_codemap( |
209 | sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest, | |
210 | ); | |
c34b1796 | 211 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
c30ab7b3 | 212 | |
5bcae85e | 213 | let mut cfg = config::build_configuration(&sess, cfg); |
e9174d1e | 214 | target_features::add_configuration(&mut cfg, &sess); |
c30ab7b3 | 215 | sess.parse_sess.config = cfg; |
85aaf69f | 216 | |
c30ab7b3 | 217 | do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess)); |
85aaf69f | 218 | |
85aaf69f | 219 | let plugins = sess.opts.debugging_opts.extra_plugins.clone(); |
a7813a04 | 220 | let control = callbacks.build_controller(&sess, &matches); |
c30ab7b3 | 221 | (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control), |
7453a54e | 222 | Some(sess)) |
85aaf69f SL |
223 | } |
224 | ||
225 | // Extract output directory and file from matches. | |
c34b1796 AL |
226 | fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) { |
227 | let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); | |
228 | let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o)); | |
85aaf69f SL |
229 | (odir, ofile) |
230 | } | |
231 | ||
232 | // Extract input (string or file and optional path) from matches. | |
c34b1796 | 233 | fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> { |
85aaf69f | 234 | if free_matches.len() == 1 { |
c34b1796 | 235 | let ifile = &free_matches[0][..]; |
85aaf69f | 236 | if ifile == "-" { |
c34b1796 AL |
237 | let mut src = String::new(); |
238 | io::stdin().read_to_string(&mut src).unwrap(); | |
54a0048b SL |
239 | Some((Input::Str { name: driver::anon_src(), input: src }, |
240 | None)) | |
85aaf69f | 241 | } else { |
92a42be0 SL |
242 | Some((Input::File(PathBuf::from(ifile)), |
243 | Some(PathBuf::from(ifile)))) | |
1a4d82fc | 244 | } |
85aaf69f SL |
245 | } else { |
246 | None | |
247 | } | |
248 | } | |
249 | ||
a7813a04 XL |
250 | fn parse_pretty(sess: &Session, |
251 | matches: &getopts::Matches) | |
252 | -> Option<(PpMode, Option<UserIdentifiedItem>)> { | |
253 | let pretty = if sess.opts.debugging_opts.unstable_options { | |
254 | matches.opt_default("pretty", "normal").map(|a| { | |
255 | // stable pretty-print variants only | |
256 | pretty::parse_pretty(sess, &a, false) | |
257 | }) | |
258 | } else { | |
259 | None | |
260 | }; | |
261 | if pretty.is_none() && sess.unstable_options() { | |
262 | matches.opt_str("unpretty").map(|a| { | |
263 | // extended with unstable pretty-print variants | |
264 | pretty::parse_pretty(sess, &a, true) | |
265 | }) | |
266 | } else { | |
267 | pretty | |
268 | } | |
269 | } | |
270 | ||
85aaf69f | 271 | // Whether to stop or continue compilation. |
c34b1796 | 272 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
85aaf69f SL |
273 | pub enum Compilation { |
274 | Stop, | |
275 | Continue, | |
276 | } | |
277 | ||
278 | impl Compilation { | |
279 | pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation { | |
280 | match self { | |
281 | Compilation::Stop => Compilation::Stop, | |
92a42be0 | 282 | Compilation::Continue => next(), |
1a4d82fc | 283 | } |
85aaf69f SL |
284 | } |
285 | } | |
1a4d82fc | 286 | |
85aaf69f SL |
287 | // A trait for customising the compilation process. Offers a number of hooks for |
288 | // executing custom code or customising input. | |
289 | pub trait CompilerCalls<'a> { | |
290 | // Hook for a callback early in the process of handling arguments. This will | |
291 | // be called straight after options have been parsed but before anything | |
292 | // else (e.g., selecting input and output). | |
293 | fn early_callback(&mut self, | |
c1a9b12d | 294 | _: &getopts::Matches, |
7453a54e | 295 | _: &config::Options, |
5bcae85e | 296 | _: &ast::CrateConfig, |
3157f602 | 297 | _: &errors::registry::Registry, |
9cc50fc6 | 298 | _: ErrorOutputType) |
c1a9b12d SL |
299 | -> Compilation { |
300 | Compilation::Continue | |
301 | } | |
85aaf69f SL |
302 | |
303 | // Hook for a callback late in the process of handling arguments. This will | |
304 | // be called just before actual compilation starts (and before build_controller | |
305 | // is called), after all arguments etc. have been completely handled. | |
306 | fn late_callback(&mut self, | |
c1a9b12d SL |
307 | _: &getopts::Matches, |
308 | _: &Session, | |
309 | _: &Input, | |
310 | _: &Option<PathBuf>, | |
311 | _: &Option<PathBuf>) | |
312 | -> Compilation { | |
313 | Compilation::Continue | |
314 | } | |
85aaf69f SL |
315 | |
316 | // Called after we extract the input from the arguments. Gives the implementer | |
317 | // an opportunity to change the inputs or to add some custom input handling. | |
318 | // The default behaviour is to simply pass through the inputs. | |
92a42be0 SL |
319 | fn some_input(&mut self, |
320 | input: Input, | |
321 | input_path: Option<PathBuf>) | |
c34b1796 | 322 | -> (Input, Option<PathBuf>) { |
85aaf69f SL |
323 | (input, input_path) |
324 | } | |
1a4d82fc | 325 | |
85aaf69f SL |
326 | // Called after we extract the input from the arguments if there is no valid |
327 | // input. Gives the implementer an opportunity to supply alternate input (by | |
328 | // returning a Some value) or to add custom behaviour for this error such as | |
329 | // emitting error messages. Returning None will cause compilation to stop | |
330 | // at this point. | |
331 | fn no_input(&mut self, | |
c1a9b12d SL |
332 | _: &getopts::Matches, |
333 | _: &config::Options, | |
5bcae85e | 334 | _: &ast::CrateConfig, |
c1a9b12d SL |
335 | _: &Option<PathBuf>, |
336 | _: &Option<PathBuf>, | |
3157f602 | 337 | _: &errors::registry::Registry) |
c1a9b12d SL |
338 | -> Option<(Input, Option<PathBuf>)> { |
339 | None | |
340 | } | |
85aaf69f | 341 | |
92a42be0 SL |
342 | // Create a CompilController struct for controlling the behaviour of |
343 | // compilation. | |
a7813a04 | 344 | fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>; |
85aaf69f SL |
345 | } |
346 | ||
347 | // CompilerCalls instance for a regular rustc build. | |
c34b1796 | 348 | #[derive(Copy, Clone)] |
85aaf69f SL |
349 | pub struct RustcDefaultCalls; |
350 | ||
7453a54e | 351 | fn handle_explain(code: &str, |
3157f602 | 352 | descriptions: &errors::registry::Registry, |
7453a54e | 353 | output: ErrorOutputType) { |
54a0048b | 354 | let normalised = if code.starts_with("E") { |
7453a54e | 355 | code.to_string() |
54a0048b SL |
356 | } else { |
357 | format!("E{0:0>4}", code) | |
7453a54e SL |
358 | }; |
359 | match descriptions.find_description(&normalised) { | |
360 | Some(ref description) => { | |
361 | // Slice off the leading newline and print. | |
a7813a04 XL |
362 | print!("{}", &(&description[1..]).split("\n").map(|x| { |
363 | format!("{}\n", if x.starts_with("```") { | |
364 | "```" | |
365 | } else { | |
366 | x | |
367 | }) | |
368 | }).collect::<String>()); | |
7453a54e SL |
369 | } |
370 | None => { | |
371 | early_error(output, &format!("no extended information for {}", code)); | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
85aaf69f SL |
376 | impl<'a> CompilerCalls<'a> for RustcDefaultCalls { |
377 | fn early_callback(&mut self, | |
378 | matches: &getopts::Matches, | |
5bcae85e | 379 | _: &config::Options, |
476ff2be | 380 | _: &ast::CrateConfig, |
3157f602 | 381 | descriptions: &errors::registry::Registry, |
9cc50fc6 | 382 | output: ErrorOutputType) |
85aaf69f | 383 | -> Compilation { |
7453a54e SL |
384 | if let Some(ref code) = matches.opt_str("explain") { |
385 | handle_explain(code, descriptions, output); | |
386 | return Compilation::Stop; | |
85aaf69f SL |
387 | } |
388 | ||
7453a54e | 389 | Compilation::Continue |
85aaf69f SL |
390 | } |
391 | ||
392 | fn no_input(&mut self, | |
393 | matches: &getopts::Matches, | |
394 | sopts: &config::Options, | |
5bcae85e | 395 | cfg: &ast::CrateConfig, |
c34b1796 AL |
396 | odir: &Option<PathBuf>, |
397 | ofile: &Option<PathBuf>, | |
3157f602 | 398 | descriptions: &errors::registry::Registry) |
c34b1796 | 399 | -> Option<(Input, Option<PathBuf>)> { |
85aaf69f SL |
400 | match matches.free.len() { |
401 | 0 => { | |
402 | if sopts.describe_lints { | |
403 | let mut ls = lint::LintStore::new(); | |
c34b1796 | 404 | rustc_lint::register_builtins(&mut ls, None); |
85aaf69f SL |
405 | describe_lints(&ls, false); |
406 | return None; | |
407 | } | |
a7813a04 | 408 | let dep_graph = DepGraph::new(sopts.build_dep_graph()); |
5bcae85e | 409 | let cstore = Rc::new(CStore::new(&dep_graph)); |
c30ab7b3 | 410 | let mut sess = build_session(sopts.clone(), |
a7813a04 XL |
411 | &dep_graph, |
412 | None, | |
413 | descriptions.clone(), | |
414 | cstore.clone()); | |
c34b1796 | 415 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
5bcae85e SL |
416 | let mut cfg = config::build_configuration(&sess, cfg.clone()); |
417 | target_features::add_configuration(&mut cfg, &sess); | |
c30ab7b3 SL |
418 | sess.parse_sess.config = cfg; |
419 | let should_stop = | |
420 | RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); | |
421 | ||
85aaf69f SL |
422 | if should_stop == Compilation::Stop { |
423 | return None; | |
424 | } | |
9cc50fc6 | 425 | early_error(sopts.error_format, "no input filename given"); |
85aaf69f SL |
426 | } |
427 | 1 => panic!("make_input should have provided valid inputs"), | |
9cc50fc6 | 428 | _ => early_error(sopts.error_format, "multiple input filenames provided"), |
85aaf69f | 429 | } |
1a4d82fc JJ |
430 | } |
431 | ||
85aaf69f SL |
432 | fn late_callback(&mut self, |
433 | matches: &getopts::Matches, | |
434 | sess: &Session, | |
435 | input: &Input, | |
c34b1796 AL |
436 | odir: &Option<PathBuf>, |
437 | ofile: &Option<PathBuf>) | |
85aaf69f | 438 | -> Compilation { |
c30ab7b3 | 439 | RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile) |
92a42be0 | 440 | .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input)) |
1a4d82fc JJ |
441 | } |
442 | ||
a7813a04 XL |
443 | fn build_controller(&mut self, |
444 | sess: &Session, | |
445 | matches: &getopts::Matches) | |
446 | -> CompileController<'a> { | |
85aaf69f SL |
447 | let mut control = CompileController::basic(); |
448 | ||
a7813a04 XL |
449 | if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { |
450 | if ppm.needs_ast_map(&opt_uii) { | |
451 | control.after_hir_lowering.stop = Compilation::Stop; | |
452 | ||
453 | control.after_parse.callback = box move |state| { | |
454 | state.krate = Some(pretty::fold_crate(state.krate.take().unwrap(), ppm)); | |
455 | }; | |
456 | control.after_hir_lowering.callback = box move |state| { | |
457 | pretty::print_after_hir_lowering(state.session, | |
32a655c1 | 458 | state.hir_map.unwrap(), |
a7813a04 XL |
459 | state.analysis.unwrap(), |
460 | state.resolutions.unwrap(), | |
461 | state.input, | |
462 | &state.expanded_crate.take().unwrap(), | |
463 | state.crate_name.unwrap(), | |
464 | ppm, | |
32a655c1 | 465 | state.arena.unwrap(), |
a7813a04 XL |
466 | state.arenas.unwrap(), |
467 | opt_uii.clone(), | |
468 | state.out_file); | |
469 | }; | |
470 | } else { | |
471 | control.after_parse.stop = Compilation::Stop; | |
472 | ||
473 | control.after_parse.callback = box move |state| { | |
474 | let krate = pretty::fold_crate(state.krate.take().unwrap(), ppm); | |
475 | pretty::print_after_parsing(state.session, | |
476 | state.input, | |
477 | &krate, | |
478 | ppm, | |
479 | state.out_file); | |
480 | }; | |
481 | } | |
482 | ||
483 | return control; | |
484 | } | |
485 | ||
5bcae85e SL |
486 | if sess.opts.debugging_opts.parse_only || |
487 | sess.opts.debugging_opts.show_span.is_some() || | |
85aaf69f SL |
488 | sess.opts.debugging_opts.ast_json_noexpand { |
489 | control.after_parse.stop = Compilation::Stop; | |
490 | } | |
491 | ||
5bcae85e SL |
492 | if sess.opts.debugging_opts.no_analysis || |
493 | sess.opts.debugging_opts.ast_json { | |
3157f602 | 494 | control.after_hir_lowering.stop = Compilation::Stop; |
85aaf69f SL |
495 | } |
496 | ||
32a655c1 SL |
497 | if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe || |
498 | i == OutputType::Metadata) { | |
85aaf69f SL |
499 | control.after_llvm.stop = Compilation::Stop; |
500 | } | |
501 | ||
a7813a04 | 502 | if save_analysis(sess) { |
85aaf69f | 503 | control.after_analysis.callback = box |state| { |
92a42be0 SL |
504 | time(state.session.time_passes(), "save analysis", || { |
505 | save::process_crate(state.tcx.unwrap(), | |
a7813a04 | 506 | state.expanded_crate.unwrap(), |
92a42be0 SL |
507 | state.analysis.unwrap(), |
508 | state.crate_name.unwrap(), | |
a7813a04 XL |
509 | state.out_dir, |
510 | save_analysis_format(state.session)) | |
92a42be0 | 511 | }); |
85aaf69f | 512 | }; |
7453a54e | 513 | control.after_analysis.run_callback_on_error = true; |
85aaf69f SL |
514 | control.make_glob_map = resolve::MakeGlobMap::Yes; |
515 | } | |
516 | ||
517 | control | |
518 | } | |
519 | } | |
520 | ||
a7813a04 XL |
521 | fn save_analysis(sess: &Session) -> bool { |
522 | sess.opts.debugging_opts.save_analysis || | |
9e0c209e SL |
523 | sess.opts.debugging_opts.save_analysis_csv || |
524 | sess.opts.debugging_opts.save_analysis_api | |
a7813a04 XL |
525 | } |
526 | ||
527 | fn save_analysis_format(sess: &Session) -> save::Format { | |
528 | if sess.opts.debugging_opts.save_analysis { | |
529 | save::Format::Json | |
530 | } else if sess.opts.debugging_opts.save_analysis_csv { | |
531 | save::Format::Csv | |
9e0c209e SL |
532 | } else if sess.opts.debugging_opts.save_analysis_api { |
533 | save::Format::JsonApi | |
a7813a04 XL |
534 | } else { |
535 | unreachable!(); | |
536 | } | |
537 | } | |
538 | ||
85aaf69f | 539 | impl RustcDefaultCalls { |
92a42be0 | 540 | pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input) -> Compilation { |
85aaf69f SL |
541 | let r = matches.opt_strs("Z"); |
542 | if r.contains(&("ls".to_string())) { | |
543 | match input { | |
544 | &Input::File(ref ifile) => { | |
85aaf69f | 545 | let path = &(*ifile); |
c34b1796 | 546 | let mut v = Vec::new(); |
c30ab7b3 | 547 | locator::list_file_metadata(&sess.target.target, path, &mut v).unwrap(); |
c34b1796 | 548 | println!("{}", String::from_utf8(v).unwrap()); |
85aaf69f | 549 | } |
54a0048b | 550 | &Input::Str { .. } => { |
9cc50fc6 | 551 | early_error(ErrorOutputType::default(), "cannot list metadata for stdin"); |
85aaf69f | 552 | } |
1a4d82fc | 553 | } |
85aaf69f | 554 | return Compilation::Stop; |
1a4d82fc | 555 | } |
85aaf69f SL |
556 | |
557 | return Compilation::Continue; | |
1a4d82fc JJ |
558 | } |
559 | ||
1a4d82fc | 560 | |
85aaf69f SL |
561 | fn print_crate_info(sess: &Session, |
562 | input: Option<&Input>, | |
c34b1796 AL |
563 | odir: &Option<PathBuf>, |
564 | ofile: &Option<PathBuf>) | |
85aaf69f | 565 | -> Compilation { |
9346a6ac | 566 | if sess.opts.prints.is_empty() { |
85aaf69f SL |
567 | return Compilation::Continue; |
568 | } | |
569 | ||
54a0048b SL |
570 | let attrs = match input { |
571 | None => None, | |
572 | Some(input) => { | |
573 | let result = parse_crate_attrs(sess, input); | |
574 | match result { | |
575 | Ok(attrs) => Some(attrs), | |
576 | Err(mut parse_error) => { | |
577 | parse_error.emit(); | |
578 | return Compilation::Stop; | |
579 | } | |
580 | } | |
581 | } | |
582 | }; | |
85aaf69f SL |
583 | for req in &sess.opts.prints { |
584 | match *req { | |
7453a54e | 585 | PrintRequest::TargetList => { |
5bcae85e | 586 | let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>(); |
7453a54e SL |
587 | targets.sort(); |
588 | println!("{}", targets.join("\n")); | |
589 | }, | |
85aaf69f | 590 | PrintRequest::Sysroot => println!("{}", sess.sysroot().display()), |
476ff2be | 591 | PrintRequest::TargetSpec => println!("{}", sess.target.target.to_json().pretty()), |
85aaf69f SL |
592 | PrintRequest::FileNames | |
593 | PrintRequest::CrateName => { | |
594 | let input = match input { | |
595 | Some(input) => input, | |
9cc50fc6 | 596 | None => early_error(ErrorOutputType::default(), "no input file provided"), |
85aaf69f SL |
597 | }; |
598 | let attrs = attrs.as_ref().unwrap(); | |
92a42be0 SL |
599 | let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess); |
600 | let id = link::find_crate_name(Some(sess), attrs, input); | |
85aaf69f SL |
601 | if *req == PrintRequest::CrateName { |
602 | println!("{}", id); | |
92a42be0 | 603 | continue; |
85aaf69f SL |
604 | } |
605 | let crate_types = driver::collect_crate_types(sess, attrs); | |
85aaf69f | 606 | for &style in &crate_types { |
92a42be0 SL |
607 | let fname = link::filename_for_input(sess, style, &id, &t_outputs); |
608 | println!("{}", | |
609 | fname.file_name() | |
610 | .unwrap() | |
611 | .to_string_lossy()); | |
85aaf69f SL |
612 | } |
613 | } | |
7453a54e | 614 | PrintRequest::Cfg => { |
9e0c209e SL |
615 | let allow_unstable_cfg = UnstableFeatures::from_environment() |
616 | .is_nightly_build(); | |
54a0048b | 617 | |
476ff2be SL |
618 | let mut cfgs = Vec::new(); |
619 | for &(name, ref value) in sess.parse_sess.config.iter() { | |
620 | let gated_cfg = GatedCfg::gate(&ast::MetaItem { | |
621 | name: name, | |
622 | node: ast::MetaItemKind::Word, | |
623 | span: DUMMY_SP, | |
624 | }); | |
625 | if !allow_unstable_cfg && gated_cfg.is_some() { | |
54a0048b SL |
626 | continue; |
627 | } | |
9e0c209e | 628 | |
476ff2be SL |
629 | cfgs.push(if let &Some(ref value) = value { |
630 | format!("{}=\"{}\"", name, value) | |
9e0c209e | 631 | } else { |
476ff2be SL |
632 | format!("{}", name) |
633 | }); | |
634 | } | |
635 | ||
636 | cfgs.sort(); | |
637 | for cfg in cfgs { | |
638 | println!("{}", cfg); | |
7453a54e SL |
639 | } |
640 | } | |
5bcae85e SL |
641 | PrintRequest::TargetCPUs => { |
642 | let tm = create_target_machine(sess); | |
643 | unsafe { llvm::LLVMRustPrintTargetCPUs(tm); } | |
644 | } | |
645 | PrintRequest::TargetFeatures => { | |
646 | let tm = create_target_machine(sess); | |
647 | unsafe { llvm::LLVMRustPrintTargetFeatures(tm); } | |
648 | } | |
649 | PrintRequest::RelocationModels => { | |
650 | println!("Available relocation models:"); | |
651 | for &(name, _) in RELOC_MODEL_ARGS.iter() { | |
652 | println!(" {}", name); | |
653 | } | |
654 | println!(""); | |
655 | } | |
656 | PrintRequest::CodeModels => { | |
657 | println!("Available code models:"); | |
658 | for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){ | |
659 | println!(" {}", name); | |
660 | } | |
661 | println!(""); | |
662 | } | |
85aaf69f SL |
663 | } |
664 | } | |
665 | return Compilation::Stop; | |
1a4d82fc JJ |
666 | } |
667 | } | |
668 | ||
669 | /// Returns a version string such as "0.12.0-dev". | |
670 | pub fn release_str() -> Option<&'static str> { | |
671 | option_env!("CFG_RELEASE") | |
672 | } | |
673 | ||
674 | /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built. | |
675 | pub fn commit_hash_str() -> Option<&'static str> { | |
676 | option_env!("CFG_VER_HASH") | |
677 | } | |
678 | ||
679 | /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string. | |
680 | pub fn commit_date_str() -> Option<&'static str> { | |
681 | option_env!("CFG_VER_DATE") | |
682 | } | |
683 | ||
c1a9b12d | 684 | /// Prints version information |
1a4d82fc JJ |
685 | pub fn version(binary: &str, matches: &getopts::Matches) { |
686 | let verbose = matches.opt_present("verbose"); | |
687 | ||
92a42be0 SL |
688 | println!("{} {}", |
689 | binary, | |
690 | option_env!("CFG_VERSION").unwrap_or("unknown version")); | |
1a4d82fc | 691 | if verbose { |
92a42be0 SL |
692 | fn unw(x: Option<&str>) -> &str { |
693 | x.unwrap_or("unknown") | |
694 | } | |
1a4d82fc JJ |
695 | println!("binary: {}", binary); |
696 | println!("commit-hash: {}", unw(commit_hash_str())); | |
697 | println!("commit-date: {}", unw(commit_date_str())); | |
698 | println!("host: {}", config::host_triple()); | |
699 | println!("release: {}", unw(release_str())); | |
c30ab7b3 SL |
700 | unsafe { |
701 | println!("LLVM version: {}.{}", | |
702 | llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor()); | |
703 | } | |
1a4d82fc JJ |
704 | } |
705 | } | |
706 | ||
707 | fn usage(verbose: bool, include_unstable_options: bool) { | |
708 | let groups = if verbose { | |
709 | config::rustc_optgroups() | |
710 | } else { | |
711 | config::rustc_short_optgroups() | |
712 | }; | |
92a42be0 SL |
713 | let groups: Vec<_> = groups.into_iter() |
714 | .filter(|x| include_unstable_options || x.is_stable()) | |
715 | .map(|x| x.opt_group) | |
716 | .collect(); | |
1a4d82fc JJ |
717 | let message = format!("Usage: rustc [OPTIONS] INPUT"); |
718 | let extra_help = if verbose { | |
719 | "" | |
720 | } else { | |
721 | "\n --help -v Print the full set of options rustc accepts" | |
722 | }; | |
92a42be0 | 723 | println!("{}\nAdditional help: |
1a4d82fc | 724 | -C help Print codegen options |
92a42be0 SL |
725 | -W help \ |
726 | Print 'lint' options and default settings | |
727 | -Z help Print internal \ | |
728 | options for debugging rustc{}\n", | |
729 | getopts::usage(&message, &groups), | |
730 | extra_help); | |
1a4d82fc JJ |
731 | } |
732 | ||
733 | fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) { | |
734 | println!(" | |
735 | Available lint options: | |
736 | -W <foo> Warn about <foo> | |
92a42be0 SL |
737 | -A <foo> \ |
738 | Allow <foo> | |
1a4d82fc | 739 | -D <foo> Deny <foo> |
92a42be0 | 740 | -F <foo> Forbid <foo> \ |
8bb4bdeb | 741 | (deny <foo> and all attempts to override) |
1a4d82fc JJ |
742 | |
743 | "); | |
744 | ||
745 | fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { | |
746 | let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); | |
747 | lints.sort_by(|x: &&Lint, y: &&Lint| { | |
748 | match x.default_level.cmp(&y.default_level) { | |
749 | // The sort doesn't case-fold but it's doubtful we care. | |
750 | Equal => x.name.cmp(y.name), | |
751 | r => r, | |
752 | } | |
753 | }); | |
754 | lints | |
755 | } | |
756 | ||
757 | fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>) | |
92a42be0 | 758 | -> Vec<(&'static str, Vec<lint::LintId>)> { |
1a4d82fc JJ |
759 | let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); |
760 | lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>), | |
761 | &(y, _): &(&'static str, Vec<lint::LintId>)| { | |
762 | x.cmp(y) | |
763 | }); | |
764 | lints | |
765 | } | |
766 | ||
767 | let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints() | |
92a42be0 SL |
768 | .iter() |
769 | .cloned() | |
770 | .partition(|&(_, p)| p); | |
1a4d82fc JJ |
771 | let plugin = sort_lints(plugin); |
772 | let builtin = sort_lints(builtin); | |
773 | ||
774 | let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups() | |
92a42be0 SL |
775 | .iter() |
776 | .cloned() | |
9e0c209e | 777 | .partition(|&(.., p)| p); |
1a4d82fc JJ |
778 | let plugin_groups = sort_lint_groups(plugin_groups); |
779 | let builtin_groups = sort_lint_groups(builtin_groups); | |
780 | ||
92a42be0 SL |
781 | let max_name_len = plugin.iter() |
782 | .chain(&builtin) | |
783 | .map(|&s| s.name.chars().count()) | |
784 | .max() | |
785 | .unwrap_or(0); | |
85aaf69f | 786 | let padded = |x: &str| { |
92a42be0 SL |
787 | let mut s = repeat(" ") |
788 | .take(max_name_len - x.chars().count()) | |
789 | .collect::<String>(); | |
1a4d82fc JJ |
790 | s.push_str(x); |
791 | s | |
792 | }; | |
793 | ||
794 | println!("Lint checks provided by rustc:\n"); | |
795 | println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); | |
796 | println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); | |
797 | ||
85aaf69f SL |
798 | let print_lints = |lints: Vec<&Lint>| { |
799 | for lint in lints { | |
1a4d82fc JJ |
800 | let name = lint.name_lower().replace("_", "-"); |
801 | println!(" {} {:7.7} {}", | |
92a42be0 SL |
802 | padded(&name[..]), |
803 | lint.default_level.as_str(), | |
804 | lint.desc); | |
1a4d82fc JJ |
805 | } |
806 | println!("\n"); | |
807 | }; | |
808 | ||
809 | print_lints(builtin); | |
810 | ||
811 | ||
812 | ||
9cc50fc6 SL |
813 | let max_name_len = max("warnings".len(), |
814 | plugin_groups.iter() | |
815 | .chain(&builtin_groups) | |
816 | .map(|&(s, _)| s.chars().count()) | |
817 | .max() | |
818 | .unwrap_or(0)); | |
819 | ||
85aaf69f | 820 | let padded = |x: &str| { |
92a42be0 SL |
821 | let mut s = repeat(" ") |
822 | .take(max_name_len - x.chars().count()) | |
823 | .collect::<String>(); | |
1a4d82fc JJ |
824 | s.push_str(x); |
825 | s | |
826 | }; | |
827 | ||
828 | println!("Lint groups provided by rustc:\n"); | |
829 | println!(" {} {}", padded("name"), "sub-lints"); | |
830 | println!(" {} {}", padded("----"), "---------"); | |
9cc50fc6 | 831 | println!(" {} {}", padded("warnings"), "all built-in lints"); |
1a4d82fc | 832 | |
85aaf69f SL |
833 | let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| { |
834 | for (name, to) in lints { | |
c34b1796 | 835 | let name = name.to_lowercase().replace("_", "-"); |
92a42be0 | 836 | let desc = to.into_iter() |
9e0c209e | 837 | .map(|x| x.to_string().replace("_", "-")) |
92a42be0 SL |
838 | .collect::<Vec<String>>() |
839 | .join(", "); | |
840 | println!(" {} {}", padded(&name[..]), desc); | |
1a4d82fc JJ |
841 | } |
842 | println!("\n"); | |
843 | }; | |
844 | ||
845 | print_lint_groups(builtin_groups); | |
846 | ||
847 | match (loaded_plugins, plugin.len(), plugin_groups.len()) { | |
848 | (false, 0, _) | (false, _, 0) => { | |
849 | println!("Compiler plugins can provide additional lints and lint groups. To see a \ | |
850 | listing of these, re-run `rustc -W help` with a crate filename."); | |
851 | } | |
9e0c209e | 852 | (false, ..) => panic!("didn't load lint plugins but got them anyway!"), |
1a4d82fc JJ |
853 | (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), |
854 | (true, l, g) => { | |
855 | if l > 0 { | |
856 | println!("Lint checks provided by plugins loaded by this crate:\n"); | |
857 | print_lints(plugin); | |
858 | } | |
859 | if g > 0 { | |
860 | println!("Lint groups provided by plugins loaded by this crate:\n"); | |
861 | print_lint_groups(plugin_groups); | |
862 | } | |
863 | } | |
864 | } | |
865 | } | |
866 | ||
867 | fn describe_debug_flags() { | |
868 | println!("\nAvailable debug options:\n"); | |
92a42be0 | 869 | print_flag_list("-Z", config::DB_OPTIONS); |
1a4d82fc JJ |
870 | } |
871 | ||
872 | fn describe_codegen_flags() { | |
873 | println!("\nAvailable codegen options:\n"); | |
92a42be0 SL |
874 | print_flag_list("-C", config::CG_OPTIONS); |
875 | } | |
876 | ||
877 | fn print_flag_list<T>(cmdline_opt: &str, | |
878 | flag_list: &[(&'static str, T, Option<&'static str>, &'static str)]) { | |
879 | let max_len = flag_list.iter() | |
880 | .map(|&(name, _, opt_type_desc, _)| { | |
881 | let extra_len = match opt_type_desc { | |
882 | Some(..) => 4, | |
883 | None => 0, | |
884 | }; | |
885 | name.chars().count() + extra_len | |
886 | }) | |
887 | .max() | |
888 | .unwrap_or(0); | |
889 | ||
890 | for &(name, _, opt_type_desc, desc) in flag_list { | |
1a4d82fc | 891 | let (width, extra) = match opt_type_desc { |
92a42be0 SL |
892 | Some(..) => (max_len - 4, "=val"), |
893 | None => (max_len, ""), | |
1a4d82fc | 894 | }; |
92a42be0 SL |
895 | println!(" {} {:>width$}{} -- {}", |
896 | cmdline_opt, | |
897 | name.replace("_", "-"), | |
898 | extra, | |
899 | desc, | |
900 | width = width); | |
1a4d82fc JJ |
901 | } |
902 | } | |
903 | ||
904 | /// Process command line options. Emits messages as appropriate. If compilation | |
7453a54e SL |
905 | /// should continue, returns a getopts::Matches object parsed from args, |
906 | /// otherwise returns None. | |
907 | /// | |
32a655c1 | 908 | /// The compiler's handling of options is a little complicated as it ties into |
7453a54e SL |
909 | /// our stability story, and it's even *more* complicated by historical |
910 | /// accidents. The current intention of each compiler option is to have one of | |
911 | /// three modes: | |
912 | /// | |
913 | /// 1. An option is stable and can be used everywhere. | |
914 | /// 2. An option is unstable, but was historically allowed on the stable | |
915 | /// channel. | |
916 | /// 3. An option is unstable, and can only be used on nightly. | |
917 | /// | |
918 | /// Like unstable library and language features, however, unstable options have | |
919 | /// always required a form of "opt in" to indicate that you're using them. This | |
920 | /// provides the easy ability to scan a code base to check to see if anything | |
921 | /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag. | |
922 | /// | |
923 | /// All options behind `-Z` are considered unstable by default. Other top-level | |
924 | /// options can also be considered unstable, and they were unlocked through the | |
925 | /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of | |
926 | /// instability in both cases, though. | |
927 | /// | |
928 | /// So with all that in mind, the comments below have some more detail about the | |
929 | /// contortions done here to get things to work out correctly. | |
54a0048b | 930 | pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { |
1a4d82fc | 931 | // Throw away the first argument, the name of the binary |
54a0048b | 932 | let args = &args[1..]; |
1a4d82fc JJ |
933 | |
934 | if args.is_empty() { | |
935 | // user did not write `-v` nor `-Z unstable-options`, so do not | |
936 | // include that extra information. | |
937 | usage(false, false); | |
938 | return None; | |
939 | } | |
940 | ||
7453a54e SL |
941 | // Parse with *all* options defined in the compiler, we don't worry about |
942 | // option stability here we just want to parse as much as possible. | |
943 | let all_groups: Vec<getopts::OptGroup> = config::rustc_optgroups() | |
944 | .into_iter() | |
945 | .map(|x| x.opt_group) | |
946 | .collect(); | |
947 | let matches = match getopts::getopts(&args[..], &all_groups) { | |
948 | Ok(m) => m, | |
949 | Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), | |
950 | }; | |
1a4d82fc | 951 | |
7453a54e SL |
952 | // For all options we just parsed, we check a few aspects: |
953 | // | |
954 | // * If the option is stable, we're all good | |
955 | // * If the option wasn't passed, we're all good | |
956 | // * If `-Z unstable-options` wasn't passed (and we're not a -Z option | |
957 | // ourselves), then we require the `-Z unstable-options` flag to unlock | |
958 | // this option that was passed. | |
959 | // * If we're a nightly compiler, then unstable options are now unlocked, so | |
960 | // we're good to go. | |
961 | // * Otherwise, if we're a truly unstable option then we generate an error | |
962 | // (unstable option being used on stable) | |
963 | // * If we're a historically stable-but-should-be-unstable option then we | |
964 | // emit a warning that we're going to turn this into an error soon. | |
54a0048b | 965 | nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); |
1a4d82fc JJ |
966 | |
967 | if matches.opt_present("h") || matches.opt_present("help") { | |
7453a54e SL |
968 | // Only show unstable options in --help if we *really* accept unstable |
969 | // options, which catches the case where we got `-Z unstable-options` on | |
970 | // the stable channel of Rust which was accidentally allowed | |
971 | // historically. | |
92a42be0 | 972 | usage(matches.opt_present("verbose"), |
54a0048b | 973 | nightly_options::is_unstable_enabled(&matches)); |
1a4d82fc JJ |
974 | return None; |
975 | } | |
976 | ||
977 | // Don't handle -W help here, because we might first load plugins. | |
1a4d82fc JJ |
978 | let r = matches.opt_strs("Z"); |
979 | if r.iter().any(|x| *x == "help") { | |
980 | describe_debug_flags(); | |
981 | return None; | |
982 | } | |
983 | ||
984 | let cg_flags = matches.opt_strs("C"); | |
985 | if cg_flags.iter().any(|x| *x == "help") { | |
986 | describe_codegen_flags(); | |
987 | return None; | |
988 | } | |
989 | ||
476ff2be SL |
990 | if cg_flags.iter().any(|x| *x == "no-stack-check") { |
991 | early_warn(ErrorOutputType::default(), | |
992 | "the --no-stack-check flag is deprecated and does nothing"); | |
993 | } | |
994 | ||
1a4d82fc | 995 | if cg_flags.contains(&"passes=list".to_string()) { |
92a42be0 SL |
996 | unsafe { |
997 | ::llvm::LLVMRustPrintPasses(); | |
998 | } | |
1a4d82fc JJ |
999 | return None; |
1000 | } | |
1001 | ||
1002 | if matches.opt_present("version") { | |
1003 | version("rustc", &matches); | |
1004 | return None; | |
1005 | } | |
1006 | ||
1007 | Some(matches) | |
1008 | } | |
1009 | ||
54a0048b SL |
1010 | fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> { |
1011 | match *input { | |
1a4d82fc | 1012 | Input::File(ref ifile) => { |
c30ab7b3 | 1013 | parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess) |
1a4d82fc | 1014 | } |
54a0048b | 1015 | Input::Str { ref name, ref input } => { |
c30ab7b3 | 1016 | parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.parse_sess) |
1a4d82fc | 1017 | } |
54a0048b | 1018 | } |
1a4d82fc JJ |
1019 | } |
1020 | ||
32a655c1 SL |
1021 | /// Runs `f` in a suitable thread for running `rustc`; returns a |
1022 | /// `Result` with either the return value of `f` or -- if a panic | |
1023 | /// occurs -- the panic value. | |
1024 | pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>> | |
1025 | where F: FnOnce() -> R + Send + 'static, | |
1026 | R: Send + 'static, | |
1027 | { | |
1028 | // Temporarily have stack size set to 16MB to deal with nom-using crates failing | |
1029 | const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB | |
1030 | ||
1031 | let mut cfg = thread::Builder::new().name("rustc".to_string()); | |
1032 | ||
1033 | // FIXME: Hacks on hacks. If the env is trying to override the stack size | |
1034 | // then *don't* set it explicitly. | |
1035 | if env::var_os("RUST_MIN_STACK").is_none() { | |
1036 | cfg = cfg.stack_size(STACK_SIZE); | |
1037 | } | |
1038 | ||
1039 | let thread = cfg.spawn(f); | |
1040 | thread.unwrap().join() | |
1041 | } | |
1042 | ||
1a4d82fc JJ |
1043 | /// Run a procedure which will detect panics in the compiler and print nicer |
1044 | /// error messages rather than just failing the test. | |
1045 | /// | |
1046 | /// The diagnostic emitter yielded to the procedure should be used for reporting | |
1047 | /// errors of the compiler. | |
92a42be0 | 1048 | pub fn monitor<F: FnOnce() + Send + 'static>(f: F) { |
c34b1796 AL |
1049 | struct Sink(Arc<Mutex<Vec<u8>>>); |
1050 | impl Write for Sink { | |
1051 | fn write(&mut self, data: &[u8]) -> io::Result<usize> { | |
1052 | Write::write(&mut *self.0.lock().unwrap(), data) | |
1053 | } | |
92a42be0 SL |
1054 | fn flush(&mut self) -> io::Result<()> { |
1055 | Ok(()) | |
1056 | } | |
c34b1796 AL |
1057 | } |
1058 | ||
1059 | let data = Arc::new(Mutex::new(Vec::new())); | |
1060 | let err = Sink(data.clone()); | |
1a4d82fc | 1061 | |
32a655c1 SL |
1062 | let result = in_rustc_thread(move || { |
1063 | io::set_panic(Some(box err)); | |
1064 | f() | |
1065 | }); | |
1a4d82fc | 1066 | |
32a655c1 | 1067 | if let Err(value) = result { |
54a0048b SL |
1068 | // Thread panicked without emitting a fatal diagnostic |
1069 | if !value.is::<errors::FatalError>() { | |
5bcae85e SL |
1070 | let emitter = |
1071 | Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None)); | |
1072 | let handler = errors::Handler::with_emitter(true, false, emitter); | |
1a4d82fc | 1073 | |
54a0048b SL |
1074 | // a .span_bug or .bug call has already printed what |
1075 | // it wants to print. | |
1076 | if !value.is::<errors::ExplicitBug>() { | |
5bcae85e SL |
1077 | handler.emit(&MultiSpan::new(), |
1078 | "unexpected panic", | |
1079 | errors::Level::Bug); | |
1a4d82fc JJ |
1080 | } |
1081 | ||
54a0048b SL |
1082 | let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(), |
1083 | format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; | |
1084 | for note in &xs { | |
5bcae85e SL |
1085 | handler.emit(&MultiSpan::new(), |
1086 | ¬e[..], | |
1087 | errors::Level::Note); | |
54a0048b SL |
1088 | } |
1089 | if match env::var_os("RUST_BACKTRACE") { | |
1090 | Some(val) => &val != "0", | |
1091 | None => false, | |
1092 | } { | |
5bcae85e | 1093 | handler.emit(&MultiSpan::new(), |
54a0048b | 1094 | "run with `RUST_BACKTRACE=1` for a backtrace", |
54a0048b SL |
1095 | errors::Level::Note); |
1096 | } | |
1097 | ||
c30ab7b3 | 1098 | writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap(); |
1a4d82fc | 1099 | } |
54a0048b SL |
1100 | |
1101 | exit_on_err(); | |
1a4d82fc JJ |
1102 | } |
1103 | } | |
1104 | ||
7453a54e SL |
1105 | fn exit_on_err() -> ! { |
1106 | // Panic so the process returns a failure code, but don't pollute the | |
1107 | // output with some unnecessary panic messages, we've already | |
1108 | // printed everything that we needed to. | |
c30ab7b3 | 1109 | io::set_panic(Some(box io::sink())); |
7453a54e SL |
1110 | panic!(); |
1111 | } | |
1112 | ||
3157f602 XL |
1113 | pub fn diagnostics_registry() -> errors::registry::Registry { |
1114 | use errors::registry::Registry; | |
85aaf69f | 1115 | |
bd371182 | 1116 | let mut all_errors = Vec::new(); |
92a42be0 SL |
1117 | all_errors.extend_from_slice(&rustc::DIAGNOSTICS); |
1118 | all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); | |
1119 | all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS); | |
1120 | all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); | |
1121 | all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); | |
1122 | all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS); | |
54a0048b | 1123 | all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS); |
9e0c209e | 1124 | all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); |
85aaf69f | 1125 | |
7453a54e | 1126 | Registry::new(&all_errors) |
85aaf69f SL |
1127 | } |
1128 | ||
1a4d82fc | 1129 | pub fn main() { |
c30ab7b3 SL |
1130 | let result = run(|| run_compiler(&env::args().collect::<Vec<_>>(), |
1131 | &mut RustcDefaultCalls, | |
1132 | None, | |
1133 | None)); | |
62682a34 | 1134 | process::exit(result as i32); |
1a4d82fc | 1135 | } |