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