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