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