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