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