]>
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 | ||
c34b1796 AL |
17 | // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) |
18 | #![cfg_attr(stage0, feature(custom_attribute))] | |
1a4d82fc | 19 | #![crate_name = "rustc_driver"] |
e9174d1e | 20 | #![unstable(feature = "rustc_private", issue = "27812")] |
1a4d82fc JJ |
21 | #![staged_api] |
22 | #![crate_type = "dylib"] | |
23 | #![crate_type = "rlib"] | |
e9174d1e | 24 | #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", |
62682a34 | 25 | html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
e9174d1e | 26 | html_root_url = "https://doc.rust-lang.org/nightly/")] |
1a4d82fc | 27 | |
1a4d82fc | 28 | #![feature(box_syntax)] |
85aaf69f | 29 | #![feature(libc)] |
85aaf69f | 30 | #![feature(quote)] |
1a4d82fc | 31 | #![feature(rustc_diagnostic_macros)] |
85aaf69f | 32 | #![feature(rustc_private)] |
c34b1796 | 33 | #![feature(set_stdio)] |
62682a34 SL |
34 | #![feature(staged_api)] |
35 | #![feature(vec_push_all)] | |
1a4d82fc JJ |
36 | |
37 | extern crate arena; | |
38 | extern crate flate; | |
39 | extern crate getopts; | |
40 | extern crate graphviz; | |
41 | extern crate libc; | |
42 | extern crate rustc; | |
43 | extern crate rustc_back; | |
44 | extern crate rustc_borrowck; | |
e9174d1e | 45 | extern crate rustc_front; |
c34b1796 | 46 | extern crate rustc_lint; |
85aaf69f | 47 | extern crate rustc_privacy; |
e9174d1e | 48 | extern crate rustc_mir; |
1a4d82fc JJ |
49 | extern crate rustc_resolve; |
50 | extern crate rustc_trans; | |
51 | extern crate rustc_typeck; | |
52 | extern crate serialize; | |
c34b1796 | 53 | extern crate rustc_llvm as llvm; |
1a4d82fc JJ |
54 | #[macro_use] extern crate log; |
55 | #[macro_use] extern crate syntax; | |
56 | ||
57 | pub use syntax::diagnostic; | |
58 | ||
85aaf69f SL |
59 | use driver::CompileController; |
60 | use pretty::{PpMode, UserIdentifiedItem}; | |
61 | ||
62 | use rustc_resolve as resolve; | |
1a4d82fc | 63 | use rustc_trans::back::link; |
85aaf69f | 64 | use rustc_trans::save; |
1a4d82fc | 65 | use rustc::session::{config, Session, build_session}; |
85aaf69f | 66 | use rustc::session::config::{Input, PrintRequest}; |
1a4d82fc JJ |
67 | use rustc::lint::Lint; |
68 | use rustc::lint; | |
69 | use rustc::metadata; | |
85aaf69f | 70 | use rustc::util::common::time; |
1a4d82fc JJ |
71 | |
72 | use std::cmp::Ordering::Equal; | |
85aaf69f | 73 | use std::env; |
c34b1796 AL |
74 | use std::io::{self, Read, Write}; |
75 | use std::iter::repeat; | |
76 | use std::path::PathBuf; | |
62682a34 | 77 | use std::process; |
c34b1796 AL |
78 | use std::str; |
79 | use std::sync::{Arc, Mutex}; | |
1a4d82fc JJ |
80 | use std::thread; |
81 | ||
82 | use rustc::session::early_error; | |
83 | ||
84 | use syntax::ast; | |
85 | use syntax::parse; | |
86 | use syntax::diagnostic::Emitter; | |
87 | use syntax::diagnostics; | |
88 | ||
89 | #[cfg(test)] | |
90 | pub mod test; | |
91 | ||
92 | pub mod driver; | |
93 | pub mod pretty; | |
e9174d1e | 94 | pub mod target_features; |
1a4d82fc | 95 | |
85aaf69f | 96 | |
c34b1796 | 97 | const BUG_REPORT_URL: &'static str = |
85aaf69f SL |
98 | "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports"; |
99 | ||
100 | ||
c34b1796 | 101 | pub fn run(args: Vec<String>) -> isize { |
85aaf69f | 102 | monitor(move || run_compiler(&args, &mut RustcDefaultCalls)); |
1a4d82fc JJ |
103 | 0 |
104 | } | |
105 | ||
85aaf69f SL |
106 | // Parse args and run the compiler. This is the primary entry point for rustc. |
107 | // See comments on CompilerCalls below for details about the callbacks argument. | |
108 | pub fn run_compiler<'a>(args: &[String], | |
109 | callbacks: &mut CompilerCalls<'a>) { | |
110 | macro_rules! do_or_return {($expr: expr) => { | |
111 | match $expr { | |
112 | Compilation::Stop => return, | |
113 | Compilation::Continue => {} | |
114 | } | |
115 | }} | |
1a4d82fc | 116 | |
1a4d82fc JJ |
117 | let matches = match handle_options(args.to_vec()) { |
118 | Some(matches) => matches, | |
119 | None => return | |
120 | }; | |
121 | ||
e9174d1e | 122 | let sopts = config::build_session_options(&matches); |
85aaf69f | 123 | |
e9174d1e | 124 | let descriptions = diagnostics_registry(); |
85aaf69f | 125 | |
e9174d1e | 126 | do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color)); |
85aaf69f SL |
127 | |
128 | let (odir, ofile) = make_output(&matches); | |
c34b1796 | 129 | let (input, input_file_path) = match make_input(&matches.free) { |
85aaf69f SL |
130 | Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), |
131 | None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) { | |
132 | Some((input, input_file_path)) => (input, input_file_path), | |
133 | None => return | |
134 | } | |
135 | }; | |
136 | ||
137 | let mut sess = build_session(sopts, input_file_path, descriptions); | |
c34b1796 | 138 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
85aaf69f SL |
139 | if sess.unstable_options() { |
140 | sess.opts.show_span = matches.opt_str("show-span"); | |
141 | } | |
e9174d1e SL |
142 | let mut cfg = config::build_configuration(&sess); |
143 | target_features::add_configuration(&mut cfg, &sess); | |
85aaf69f SL |
144 | |
145 | do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); | |
146 | ||
147 | // It is somewhat unfortunate that this is hardwired in - this is forced by | |
148 | // the fact that pretty_print_input requires the session by value. | |
149 | let pretty = callbacks.parse_pretty(&sess, &matches); | |
150 | match pretty { | |
151 | Some((ppm, opt_uii)) => { | |
152 | pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile); | |
1a4d82fc | 153 | return; |
85aaf69f SL |
154 | } |
155 | None => {/* continue */ } | |
1a4d82fc JJ |
156 | } |
157 | ||
85aaf69f SL |
158 | let plugins = sess.opts.debugging_opts.extra_plugins.clone(); |
159 | let control = callbacks.build_controller(&sess); | |
160 | driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control); | |
161 | } | |
162 | ||
163 | // Extract output directory and file from matches. | |
c34b1796 AL |
164 | fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) { |
165 | let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); | |
166 | let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o)); | |
85aaf69f SL |
167 | (odir, ofile) |
168 | } | |
169 | ||
170 | // Extract input (string or file and optional path) from matches. | |
c34b1796 | 171 | fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> { |
85aaf69f | 172 | if free_matches.len() == 1 { |
c34b1796 | 173 | let ifile = &free_matches[0][..]; |
85aaf69f | 174 | if ifile == "-" { |
c34b1796 AL |
175 | let mut src = String::new(); |
176 | io::stdin().read_to_string(&mut src).unwrap(); | |
85aaf69f SL |
177 | Some((Input::Str(src), None)) |
178 | } else { | |
c34b1796 | 179 | Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))) |
1a4d82fc | 180 | } |
85aaf69f SL |
181 | } else { |
182 | None | |
183 | } | |
184 | } | |
185 | ||
186 | // Whether to stop or continue compilation. | |
c34b1796 | 187 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
85aaf69f SL |
188 | pub enum Compilation { |
189 | Stop, | |
190 | Continue, | |
191 | } | |
192 | ||
193 | impl Compilation { | |
194 | pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation { | |
195 | match self { | |
196 | Compilation::Stop => Compilation::Stop, | |
197 | Compilation::Continue => next() | |
1a4d82fc | 198 | } |
85aaf69f SL |
199 | } |
200 | } | |
1a4d82fc | 201 | |
85aaf69f SL |
202 | // A trait for customising the compilation process. Offers a number of hooks for |
203 | // executing custom code or customising input. | |
204 | pub trait CompilerCalls<'a> { | |
205 | // Hook for a callback early in the process of handling arguments. This will | |
206 | // be called straight after options have been parsed but before anything | |
207 | // else (e.g., selecting input and output). | |
208 | fn early_callback(&mut self, | |
c1a9b12d | 209 | _: &getopts::Matches, |
e9174d1e SL |
210 | _: &diagnostics::registry::Registry, |
211 | _: diagnostic::ColorConfig) | |
c1a9b12d SL |
212 | -> Compilation { |
213 | Compilation::Continue | |
214 | } | |
85aaf69f SL |
215 | |
216 | // Hook for a callback late in the process of handling arguments. This will | |
217 | // be called just before actual compilation starts (and before build_controller | |
218 | // is called), after all arguments etc. have been completely handled. | |
219 | fn late_callback(&mut self, | |
c1a9b12d SL |
220 | _: &getopts::Matches, |
221 | _: &Session, | |
222 | _: &Input, | |
223 | _: &Option<PathBuf>, | |
224 | _: &Option<PathBuf>) | |
225 | -> Compilation { | |
226 | Compilation::Continue | |
227 | } | |
85aaf69f SL |
228 | |
229 | // Called after we extract the input from the arguments. Gives the implementer | |
230 | // an opportunity to change the inputs or to add some custom input handling. | |
231 | // The default behaviour is to simply pass through the inputs. | |
c34b1796 AL |
232 | fn some_input(&mut self, input: Input, input_path: Option<PathBuf>) |
233 | -> (Input, Option<PathBuf>) { | |
85aaf69f SL |
234 | (input, input_path) |
235 | } | |
1a4d82fc | 236 | |
85aaf69f SL |
237 | // Called after we extract the input from the arguments if there is no valid |
238 | // input. Gives the implementer an opportunity to supply alternate input (by | |
239 | // returning a Some value) or to add custom behaviour for this error such as | |
240 | // emitting error messages. Returning None will cause compilation to stop | |
241 | // at this point. | |
242 | fn no_input(&mut self, | |
c1a9b12d SL |
243 | _: &getopts::Matches, |
244 | _: &config::Options, | |
245 | _: &Option<PathBuf>, | |
246 | _: &Option<PathBuf>, | |
247 | _: &diagnostics::registry::Registry) | |
248 | -> Option<(Input, Option<PathBuf>)> { | |
249 | None | |
250 | } | |
85aaf69f SL |
251 | |
252 | // Parse pretty printing information from the arguments. The implementer can | |
253 | // choose to ignore this (the default will return None) which will skip pretty | |
254 | // printing. If you do want to pretty print, it is recommended to use the | |
255 | // implementation of this method from RustcDefaultCalls. | |
256 | // FIXME, this is a terrible bit of API. Parsing of pretty printing stuff | |
257 | // should be done as part of the framework and the implementor should customise | |
258 | // handling of it. However, that is not possible atm because pretty printing | |
259 | // essentially goes off and takes another path through the compiler which | |
260 | // means the session is either moved or not depending on what parse_pretty | |
261 | // returns (we could fix this by cloning, but it's another hack). The proper | |
262 | // solution is to handle pretty printing as if it were a compiler extension, | |
263 | // extending CompileController to make this work (see for example the treatment | |
264 | // of save-analysis in RustcDefaultCalls::build_controller). | |
265 | fn parse_pretty(&mut self, | |
266 | _sess: &Session, | |
267 | _matches: &getopts::Matches) | |
268 | -> Option<(PpMode, Option<UserIdentifiedItem>)> { | |
269 | None | |
270 | } | |
1a4d82fc | 271 | |
85aaf69f SL |
272 | // Create a CompilController struct for controlling the behaviour of compilation. |
273 | fn build_controller(&mut self, &Session) -> CompileController<'a>; | |
274 | } | |
275 | ||
276 | // CompilerCalls instance for a regular rustc build. | |
c34b1796 | 277 | #[derive(Copy, Clone)] |
85aaf69f SL |
278 | pub struct RustcDefaultCalls; |
279 | ||
280 | impl<'a> CompilerCalls<'a> for RustcDefaultCalls { | |
281 | fn early_callback(&mut self, | |
282 | matches: &getopts::Matches, | |
e9174d1e SL |
283 | descriptions: &diagnostics::registry::Registry, |
284 | color: diagnostic::ColorConfig) | |
85aaf69f SL |
285 | -> Compilation { |
286 | match matches.opt_str("explain") { | |
287 | Some(ref code) => { | |
288 | match descriptions.find_description(&code[..]) { | |
289 | Some(ref description) => { | |
9346a6ac AL |
290 | // Slice off the leading newline and print. |
291 | print!("{}", &description[1..]); | |
85aaf69f SL |
292 | } |
293 | None => { | |
e9174d1e | 294 | early_error(color, &format!("no extended information for {}", code)); |
85aaf69f SL |
295 | } |
296 | } | |
297 | return Compilation::Stop; | |
298 | }, | |
299 | None => () | |
300 | } | |
301 | ||
302 | return Compilation::Continue; | |
303 | } | |
304 | ||
305 | fn no_input(&mut self, | |
306 | matches: &getopts::Matches, | |
307 | sopts: &config::Options, | |
c34b1796 AL |
308 | odir: &Option<PathBuf>, |
309 | ofile: &Option<PathBuf>, | |
85aaf69f | 310 | descriptions: &diagnostics::registry::Registry) |
c34b1796 | 311 | -> Option<(Input, Option<PathBuf>)> { |
85aaf69f SL |
312 | match matches.free.len() { |
313 | 0 => { | |
314 | if sopts.describe_lints { | |
315 | let mut ls = lint::LintStore::new(); | |
c34b1796 | 316 | rustc_lint::register_builtins(&mut ls, None); |
85aaf69f SL |
317 | describe_lints(&ls, false); |
318 | return None; | |
319 | } | |
320 | let sess = build_session(sopts.clone(), None, descriptions.clone()); | |
c34b1796 | 321 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
85aaf69f SL |
322 | let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); |
323 | if should_stop == Compilation::Stop { | |
324 | return None; | |
325 | } | |
e9174d1e | 326 | early_error(sopts.color, "no input filename given"); |
85aaf69f SL |
327 | } |
328 | 1 => panic!("make_input should have provided valid inputs"), | |
e9174d1e | 329 | _ => early_error(sopts.color, "multiple input filenames provided") |
85aaf69f SL |
330 | } |
331 | ||
332 | None | |
1a4d82fc JJ |
333 | } |
334 | ||
85aaf69f SL |
335 | fn parse_pretty(&mut self, |
336 | sess: &Session, | |
337 | matches: &getopts::Matches) | |
338 | -> Option<(PpMode, Option<UserIdentifiedItem>)> { | |
339 | let pretty = if sess.opts.debugging_opts.unstable_options { | |
340 | matches.opt_default("pretty", "normal").map(|a| { | |
341 | // stable pretty-print variants only | |
342 | pretty::parse_pretty(sess, &a, false) | |
343 | }) | |
344 | } else { | |
345 | None | |
346 | }; | |
347 | if pretty.is_none() && sess.unstable_options() { | |
c1a9b12d | 348 | matches.opt_str("unpretty").map(|a| { |
1a4d82fc | 349 | // extended with unstable pretty-print variants |
85aaf69f | 350 | pretty::parse_pretty(sess, &a, true) |
1a4d82fc JJ |
351 | }) |
352 | } else { | |
353 | pretty | |
1a4d82fc | 354 | } |
1a4d82fc JJ |
355 | } |
356 | ||
85aaf69f SL |
357 | fn late_callback(&mut self, |
358 | matches: &getopts::Matches, | |
359 | sess: &Session, | |
360 | input: &Input, | |
c34b1796 AL |
361 | odir: &Option<PathBuf>, |
362 | ofile: &Option<PathBuf>) | |
85aaf69f SL |
363 | -> Compilation { |
364 | RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile).and_then( | |
365 | || RustcDefaultCalls::list_metadata(sess, matches, input)) | |
1a4d82fc JJ |
366 | } |
367 | ||
85aaf69f SL |
368 | fn build_controller(&mut self, sess: &Session) -> CompileController<'a> { |
369 | let mut control = CompileController::basic(); | |
370 | ||
371 | if sess.opts.parse_only || | |
372 | sess.opts.show_span.is_some() || | |
373 | sess.opts.debugging_opts.ast_json_noexpand { | |
374 | control.after_parse.stop = Compilation::Stop; | |
375 | } | |
376 | ||
377 | if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json { | |
378 | control.after_write_deps.stop = Compilation::Stop; | |
379 | } | |
380 | ||
381 | if sess.opts.no_trans { | |
382 | control.after_analysis.stop = Compilation::Stop; | |
383 | } | |
384 | ||
385 | if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) { | |
386 | control.after_llvm.stop = Compilation::Stop; | |
387 | } | |
388 | ||
389 | if sess.opts.debugging_opts.save_analysis { | |
390 | control.after_analysis.callback = box |state| { | |
c34b1796 | 391 | time(state.session.time_passes(), |
e9174d1e SL |
392 | "save analysis", |
393 | || save::process_crate(state.tcx.unwrap(), | |
394 | state.krate.unwrap(), | |
395 | state.analysis.unwrap(), | |
396 | state.out_dir)); | |
85aaf69f SL |
397 | }; |
398 | control.make_glob_map = resolve::MakeGlobMap::Yes; | |
399 | } | |
400 | ||
401 | control | |
402 | } | |
403 | } | |
404 | ||
405 | impl RustcDefaultCalls { | |
406 | pub fn list_metadata(sess: &Session, | |
407 | matches: &getopts::Matches, | |
408 | input: &Input) | |
409 | -> Compilation { | |
410 | let r = matches.opt_strs("Z"); | |
411 | if r.contains(&("ls".to_string())) { | |
412 | match input { | |
413 | &Input::File(ref ifile) => { | |
85aaf69f | 414 | let path = &(*ifile); |
c34b1796 | 415 | let mut v = Vec::new(); |
62682a34 | 416 | metadata::loader::list_file_metadata(&sess.target.target, |
85aaf69f | 417 | path, |
c34b1796 AL |
418 | &mut v).unwrap(); |
419 | println!("{}", String::from_utf8(v).unwrap()); | |
85aaf69f SL |
420 | } |
421 | &Input::Str(_) => { | |
e9174d1e | 422 | early_error(sess.opts.color, "cannot list metadata for stdin"); |
85aaf69f | 423 | } |
1a4d82fc | 424 | } |
85aaf69f | 425 | return Compilation::Stop; |
1a4d82fc | 426 | } |
85aaf69f SL |
427 | |
428 | return Compilation::Continue; | |
1a4d82fc JJ |
429 | } |
430 | ||
1a4d82fc | 431 | |
85aaf69f SL |
432 | fn print_crate_info(sess: &Session, |
433 | input: Option<&Input>, | |
c34b1796 AL |
434 | odir: &Option<PathBuf>, |
435 | ofile: &Option<PathBuf>) | |
85aaf69f | 436 | -> Compilation { |
9346a6ac | 437 | if sess.opts.prints.is_empty() { |
85aaf69f SL |
438 | return Compilation::Continue; |
439 | } | |
440 | ||
441 | let attrs = input.map(|input| parse_crate_attrs(sess, input)); | |
442 | for req in &sess.opts.prints { | |
443 | match *req { | |
444 | PrintRequest::Sysroot => println!("{}", sess.sysroot().display()), | |
445 | PrintRequest::FileNames | | |
446 | PrintRequest::CrateName => { | |
447 | let input = match input { | |
448 | Some(input) => input, | |
e9174d1e | 449 | None => early_error(sess.opts.color, "no input file provided"), |
85aaf69f SL |
450 | }; |
451 | let attrs = attrs.as_ref().unwrap(); | |
452 | let t_outputs = driver::build_output_filenames(input, | |
453 | odir, | |
454 | ofile, | |
455 | attrs, | |
456 | sess); | |
457 | let id = link::find_crate_name(Some(sess), | |
458 | attrs, | |
459 | input); | |
460 | if *req == PrintRequest::CrateName { | |
461 | println!("{}", id); | |
462 | continue | |
463 | } | |
464 | let crate_types = driver::collect_crate_types(sess, attrs); | |
465 | let metadata = driver::collect_crate_metadata(sess, attrs); | |
466 | *sess.crate_metadata.borrow_mut() = metadata; | |
467 | for &style in &crate_types { | |
c1a9b12d SL |
468 | let fname = link::filename_for_input(sess, style, &id, |
469 | &t_outputs); | |
c34b1796 AL |
470 | println!("{}", fname.file_name().unwrap() |
471 | .to_string_lossy()); | |
85aaf69f SL |
472 | } |
473 | } | |
474 | } | |
475 | } | |
476 | return Compilation::Stop; | |
1a4d82fc JJ |
477 | } |
478 | } | |
479 | ||
480 | /// Returns a version string such as "0.12.0-dev". | |
481 | pub fn release_str() -> Option<&'static str> { | |
482 | option_env!("CFG_RELEASE") | |
483 | } | |
484 | ||
485 | /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built. | |
486 | pub fn commit_hash_str() -> Option<&'static str> { | |
487 | option_env!("CFG_VER_HASH") | |
488 | } | |
489 | ||
490 | /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string. | |
491 | pub fn commit_date_str() -> Option<&'static str> { | |
492 | option_env!("CFG_VER_DATE") | |
493 | } | |
494 | ||
c1a9b12d | 495 | /// Prints version information |
1a4d82fc JJ |
496 | pub fn version(binary: &str, matches: &getopts::Matches) { |
497 | let verbose = matches.opt_present("verbose"); | |
498 | ||
499 | println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version")); | |
500 | if verbose { | |
501 | fn unw(x: Option<&str>) -> &str { x.unwrap_or("unknown") } | |
502 | println!("binary: {}", binary); | |
503 | println!("commit-hash: {}", unw(commit_hash_str())); | |
504 | println!("commit-date: {}", unw(commit_date_str())); | |
505 | println!("host: {}", config::host_triple()); | |
506 | println!("release: {}", unw(release_str())); | |
507 | } | |
508 | } | |
509 | ||
510 | fn usage(verbose: bool, include_unstable_options: bool) { | |
511 | let groups = if verbose { | |
512 | config::rustc_optgroups() | |
513 | } else { | |
514 | config::rustc_short_optgroups() | |
515 | }; | |
516 | let groups : Vec<_> = groups.into_iter() | |
517 | .filter(|x| include_unstable_options || x.is_stable()) | |
518 | .map(|x|x.opt_group) | |
519 | .collect(); | |
520 | let message = format!("Usage: rustc [OPTIONS] INPUT"); | |
521 | let extra_help = if verbose { | |
522 | "" | |
523 | } else { | |
524 | "\n --help -v Print the full set of options rustc accepts" | |
525 | }; | |
526 | println!("{}\n\ | |
527 | Additional help: | |
528 | -C help Print codegen options | |
529 | -W help Print 'lint' options and default settings | |
530 | -Z help Print internal options for debugging rustc{}\n", | |
85aaf69f | 531 | getopts::usage(&message, &groups), |
1a4d82fc JJ |
532 | extra_help); |
533 | } | |
534 | ||
535 | fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) { | |
536 | println!(" | |
537 | Available lint options: | |
538 | -W <foo> Warn about <foo> | |
539 | -A <foo> Allow <foo> | |
540 | -D <foo> Deny <foo> | |
541 | -F <foo> Forbid <foo> (deny, and deny all overrides) | |
542 | ||
543 | "); | |
544 | ||
545 | fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { | |
546 | let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); | |
547 | lints.sort_by(|x: &&Lint, y: &&Lint| { | |
548 | match x.default_level.cmp(&y.default_level) { | |
549 | // The sort doesn't case-fold but it's doubtful we care. | |
550 | Equal => x.name.cmp(y.name), | |
551 | r => r, | |
552 | } | |
553 | }); | |
554 | lints | |
555 | } | |
556 | ||
557 | fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>) | |
558 | -> Vec<(&'static str, Vec<lint::LintId>)> { | |
559 | let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); | |
560 | lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>), | |
561 | &(y, _): &(&'static str, Vec<lint::LintId>)| { | |
562 | x.cmp(y) | |
563 | }); | |
564 | lints | |
565 | } | |
566 | ||
567 | let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints() | |
568 | .iter().cloned().partition(|&(_, p)| p); | |
569 | let plugin = sort_lints(plugin); | |
570 | let builtin = sort_lints(builtin); | |
571 | ||
572 | let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups() | |
573 | .iter().cloned().partition(|&(_, _, p)| p); | |
574 | let plugin_groups = sort_lint_groups(plugin_groups); | |
575 | let builtin_groups = sort_lint_groups(builtin_groups); | |
576 | ||
62682a34 | 577 | let max_name_len = plugin.iter().chain(&builtin) |
d9579d0f | 578 | .map(|&s| s.name.chars().count()) |
1a4d82fc | 579 | .max().unwrap_or(0); |
85aaf69f | 580 | let padded = |x: &str| { |
1a4d82fc JJ |
581 | let mut s = repeat(" ").take(max_name_len - x.chars().count()) |
582 | .collect::<String>(); | |
583 | s.push_str(x); | |
584 | s | |
585 | }; | |
586 | ||
587 | println!("Lint checks provided by rustc:\n"); | |
588 | println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); | |
589 | println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); | |
590 | ||
85aaf69f SL |
591 | let print_lints = |lints: Vec<&Lint>| { |
592 | for lint in lints { | |
1a4d82fc JJ |
593 | let name = lint.name_lower().replace("_", "-"); |
594 | println!(" {} {:7.7} {}", | |
85aaf69f | 595 | padded(&name[..]), lint.default_level.as_str(), lint.desc); |
1a4d82fc JJ |
596 | } |
597 | println!("\n"); | |
598 | }; | |
599 | ||
600 | print_lints(builtin); | |
601 | ||
602 | ||
603 | ||
62682a34 | 604 | let max_name_len = plugin_groups.iter().chain(&builtin_groups) |
d9579d0f | 605 | .map(|&(s, _)| s.chars().count()) |
1a4d82fc | 606 | .max().unwrap_or(0); |
85aaf69f | 607 | let padded = |x: &str| { |
1a4d82fc JJ |
608 | let mut s = repeat(" ").take(max_name_len - x.chars().count()) |
609 | .collect::<String>(); | |
610 | s.push_str(x); | |
611 | s | |
612 | }; | |
613 | ||
614 | println!("Lint groups provided by rustc:\n"); | |
615 | println!(" {} {}", padded("name"), "sub-lints"); | |
616 | println!(" {} {}", padded("----"), "---------"); | |
617 | ||
85aaf69f SL |
618 | let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| { |
619 | for (name, to) in lints { | |
c34b1796 | 620 | let name = name.to_lowercase().replace("_", "-"); |
1a4d82fc | 621 | let desc = to.into_iter().map(|x| x.as_str().replace("_", "-")) |
c1a9b12d | 622 | .collect::<Vec<String>>().join(", "); |
1a4d82fc | 623 | println!(" {} {}", |
85aaf69f | 624 | padded(&name[..]), desc); |
1a4d82fc JJ |
625 | } |
626 | println!("\n"); | |
627 | }; | |
628 | ||
629 | print_lint_groups(builtin_groups); | |
630 | ||
631 | match (loaded_plugins, plugin.len(), plugin_groups.len()) { | |
632 | (false, 0, _) | (false, _, 0) => { | |
633 | println!("Compiler plugins can provide additional lints and lint groups. To see a \ | |
634 | listing of these, re-run `rustc -W help` with a crate filename."); | |
635 | } | |
636 | (false, _, _) => panic!("didn't load lint plugins but got them anyway!"), | |
637 | (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), | |
638 | (true, l, g) => { | |
639 | if l > 0 { | |
640 | println!("Lint checks provided by plugins loaded by this crate:\n"); | |
641 | print_lints(plugin); | |
642 | } | |
643 | if g > 0 { | |
644 | println!("Lint groups provided by plugins loaded by this crate:\n"); | |
645 | print_lint_groups(plugin_groups); | |
646 | } | |
647 | } | |
648 | } | |
649 | } | |
650 | ||
651 | fn describe_debug_flags() { | |
652 | println!("\nAvailable debug options:\n"); | |
85aaf69f | 653 | for &(name, _, opt_type_desc, desc) in config::DB_OPTIONS { |
1a4d82fc JJ |
654 | let (width, extra) = match opt_type_desc { |
655 | Some(..) => (21, "=val"), | |
656 | None => (25, "") | |
657 | }; | |
658 | println!(" -Z {:>width$}{} -- {}", name.replace("_", "-"), | |
659 | extra, desc, width=width); | |
660 | } | |
661 | } | |
662 | ||
663 | fn describe_codegen_flags() { | |
664 | println!("\nAvailable codegen options:\n"); | |
85aaf69f | 665 | for &(name, _, opt_type_desc, desc) in config::CG_OPTIONS { |
1a4d82fc JJ |
666 | let (width, extra) = match opt_type_desc { |
667 | Some(..) => (21, "=val"), | |
668 | None => (25, "") | |
669 | }; | |
670 | println!(" -C {:>width$}{} -- {}", name.replace("_", "-"), | |
671 | extra, desc, width=width); | |
672 | } | |
673 | } | |
674 | ||
675 | /// Process command line options. Emits messages as appropriate. If compilation | |
676 | /// should continue, returns a getopts::Matches object parsed from args, otherwise | |
677 | /// returns None. | |
678 | pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> { | |
679 | // Throw away the first argument, the name of the binary | |
680 | let _binary = args.remove(0); | |
681 | ||
682 | if args.is_empty() { | |
683 | // user did not write `-v` nor `-Z unstable-options`, so do not | |
684 | // include that extra information. | |
685 | usage(false, false); | |
686 | return None; | |
687 | } | |
688 | ||
c34b1796 AL |
689 | fn allows_unstable_options(matches: &getopts::Matches) -> bool { |
690 | let r = matches.opt_strs("Z"); | |
691 | r.iter().any(|x| *x == "unstable-options") | |
692 | } | |
693 | ||
694 | fn parse_all_options(args: &Vec<String>) -> getopts::Matches { | |
695 | let all_groups : Vec<getopts::OptGroup> | |
696 | = config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect(); | |
697 | match getopts::getopts(&args[..], &all_groups) { | |
698 | Ok(m) => { | |
699 | if !allows_unstable_options(&m) { | |
700 | // If -Z unstable-options was not specified, verify that | |
701 | // no unstable options were present. | |
702 | for opt in config::rustc_optgroups().into_iter().filter(|x| !x.is_stable()) { | |
703 | let opt_name = if !opt.opt_group.long_name.is_empty() { | |
704 | &opt.opt_group.long_name | |
1a4d82fc | 705 | } else { |
c34b1796 AL |
706 | &opt.opt_group.short_name |
707 | }; | |
708 | if m.opt_present(opt_name) { | |
e9174d1e SL |
709 | early_error(diagnostic::Auto, &format!("use of unstable option '{}' \ |
710 | requires -Z unstable-options", | |
711 | opt_name)); | |
1a4d82fc JJ |
712 | } |
713 | } | |
1a4d82fc | 714 | } |
c34b1796 | 715 | m |
1a4d82fc | 716 | } |
e9174d1e | 717 | Err(f) => early_error(diagnostic::Auto, &f.to_string()) |
c34b1796 AL |
718 | } |
719 | } | |
1a4d82fc | 720 | |
c34b1796 AL |
721 | // As a speed optimization, first try to parse the command-line using just |
722 | // the stable options. | |
723 | let matches = match getopts::getopts(&args[..], &config::optgroups()) { | |
724 | Ok(ref m) if allows_unstable_options(m) => { | |
725 | // If -Z unstable-options was specified, redo parsing with the | |
726 | // unstable options to ensure that unstable options are defined | |
727 | // in the returned getopts::Matches. | |
728 | parse_all_options(&args) | |
729 | } | |
730 | Ok(m) => m, | |
731 | Err(_) => { | |
732 | // redo option parsing, including unstable options this time, | |
733 | // in anticipation that the mishandled option was one of the | |
734 | // unstable ones. | |
735 | parse_all_options(&args) | |
736 | } | |
737 | }; | |
1a4d82fc JJ |
738 | |
739 | if matches.opt_present("h") || matches.opt_present("help") { | |
c34b1796 | 740 | usage(matches.opt_present("verbose"), allows_unstable_options(&matches)); |
1a4d82fc JJ |
741 | return None; |
742 | } | |
743 | ||
744 | // Don't handle -W help here, because we might first load plugins. | |
745 | ||
746 | let r = matches.opt_strs("Z"); | |
747 | if r.iter().any(|x| *x == "help") { | |
748 | describe_debug_flags(); | |
749 | return None; | |
750 | } | |
751 | ||
752 | let cg_flags = matches.opt_strs("C"); | |
753 | if cg_flags.iter().any(|x| *x == "help") { | |
754 | describe_codegen_flags(); | |
755 | return None; | |
756 | } | |
757 | ||
758 | if cg_flags.contains(&"passes=list".to_string()) { | |
759 | unsafe { ::llvm::LLVMRustPrintPasses(); } | |
760 | return None; | |
761 | } | |
762 | ||
763 | if matches.opt_present("version") { | |
764 | version("rustc", &matches); | |
765 | return None; | |
766 | } | |
767 | ||
768 | Some(matches) | |
769 | } | |
770 | ||
1a4d82fc JJ |
771 | fn parse_crate_attrs(sess: &Session, input: &Input) -> |
772 | Vec<ast::Attribute> { | |
773 | let result = match *input { | |
774 | Input::File(ref ifile) => { | |
775 | parse::parse_crate_attrs_from_file(ifile, | |
776 | Vec::new(), | |
777 | &sess.parse_sess) | |
778 | } | |
779 | Input::Str(ref src) => { | |
780 | parse::parse_crate_attrs_from_source_str( | |
781 | driver::anon_src().to_string(), | |
782 | src.to_string(), | |
783 | Vec::new(), | |
784 | &sess.parse_sess) | |
785 | } | |
786 | }; | |
787 | result.into_iter().collect() | |
788 | } | |
789 | ||
1a4d82fc JJ |
790 | /// Run a procedure which will detect panics in the compiler and print nicer |
791 | /// error messages rather than just failing the test. | |
792 | /// | |
793 | /// The diagnostic emitter yielded to the procedure should be used for reporting | |
794 | /// errors of the compiler. | |
85aaf69f | 795 | pub fn monitor<F:FnOnce()+Send+'static>(f: F) { |
c34b1796 | 796 | const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB |
1a4d82fc | 797 | |
c34b1796 AL |
798 | struct Sink(Arc<Mutex<Vec<u8>>>); |
799 | impl Write for Sink { | |
800 | fn write(&mut self, data: &[u8]) -> io::Result<usize> { | |
801 | Write::write(&mut *self.0.lock().unwrap(), data) | |
802 | } | |
803 | fn flush(&mut self) -> io::Result<()> { Ok(()) } | |
804 | } | |
805 | ||
806 | let data = Arc::new(Mutex::new(Vec::new())); | |
807 | let err = Sink(data.clone()); | |
1a4d82fc JJ |
808 | |
809 | let mut cfg = thread::Builder::new().name("rustc".to_string()); | |
810 | ||
811 | // FIXME: Hacks on hacks. If the env is trying to override the stack size | |
812 | // then *don't* set it explicitly. | |
85aaf69f | 813 | if env::var_os("RUST_MIN_STACK").is_none() { |
1a4d82fc JJ |
814 | cfg = cfg.stack_size(STACK_SIZE); |
815 | } | |
816 | ||
c34b1796 | 817 | match cfg.spawn(move || { io::set_panic(box err); f() }).unwrap().join() { |
1a4d82fc JJ |
818 | Ok(()) => { /* fallthrough */ } |
819 | Err(value) => { | |
820 | // Thread panicked without emitting a fatal diagnostic | |
821 | if !value.is::<diagnostic::FatalError>() { | |
822 | let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); | |
823 | ||
824 | // a .span_bug or .bug call has already printed what | |
825 | // it wants to print. | |
826 | if !value.is::<diagnostic::ExplicitBug>() { | |
827 | emitter.emit( | |
828 | None, | |
829 | "unexpected panic", | |
830 | None, | |
831 | diagnostic::Bug); | |
832 | } | |
833 | ||
834 | let xs = [ | |
835 | "the compiler unexpectedly panicked. this is a bug.".to_string(), | |
836 | format!("we would appreciate a bug report: {}", | |
837 | BUG_REPORT_URL), | |
1a4d82fc | 838 | ]; |
85aaf69f SL |
839 | for note in &xs { |
840 | emitter.emit(None, ¬e[..], None, diagnostic::Note) | |
1a4d82fc | 841 | } |
62682a34 SL |
842 | if let None = env::var_os("RUST_BACKTRACE") { |
843 | emitter.emit(None, "run with `RUST_BACKTRACE=1` for a backtrace", | |
844 | None, diagnostic::Note); | |
845 | } | |
1a4d82fc | 846 | |
c34b1796 | 847 | println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); |
1a4d82fc JJ |
848 | } |
849 | ||
850 | // Panic so the process returns a failure code, but don't pollute the | |
851 | // output with some unnecessary panic messages, we've already | |
852 | // printed everything that we needed to. | |
c34b1796 | 853 | io::set_panic(box io::sink()); |
1a4d82fc JJ |
854 | panic!(); |
855 | } | |
856 | } | |
857 | } | |
858 | ||
85aaf69f SL |
859 | pub fn diagnostics_registry() -> diagnostics::registry::Registry { |
860 | use syntax::diagnostics::registry::Registry; | |
861 | ||
bd371182 | 862 | let mut all_errors = Vec::new(); |
d9579d0f AL |
863 | all_errors.push_all(&rustc::DIAGNOSTICS); |
864 | all_errors.push_all(&rustc_typeck::DIAGNOSTICS); | |
865 | all_errors.push_all(&rustc_borrowck::DIAGNOSTICS); | |
866 | all_errors.push_all(&rustc_resolve::DIAGNOSTICS); | |
85aaf69f SL |
867 | |
868 | Registry::new(&*all_errors) | |
869 | } | |
870 | ||
1a4d82fc | 871 | pub fn main() { |
85aaf69f | 872 | let result = run(env::args().collect()); |
62682a34 | 873 | process::exit(result as i32); |
1a4d82fc | 874 | } |