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