]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/lib.rs
22c26b0643050546ca85a90e255c0254e25537b1
[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 extern crate rustc_trans_utils;
51 extern crate rustc_typeck;
52 extern crate serialize;
53 #[macro_use]
54 extern crate log;
55 extern crate syntax;
56 extern crate syntax_ext;
57 extern crate syntax_pos;
58
59 use driver::CompileController;
60 use pretty::{PpMode, UserIdentifiedItem};
61
62 use rustc_resolve as resolve;
63 use rustc_save_analysis as save;
64 use rustc_save_analysis::DumpHandler;
65 use rustc::session::{self, config, Session, build_session, CompileResult};
66 use rustc::session::CompileIncomplete;
67 use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
68 use rustc::session::config::nightly_options;
69 use rustc::session::filesearch;
70 use rustc::session::{early_error, early_warn};
71 use rustc::lint::Lint;
72 use rustc::lint;
73 use rustc::middle::cstore::CrateStore;
74 use rustc_metadata::locator;
75 use rustc_metadata::cstore::CStore;
76 use rustc_metadata::dynamic_lib::DynamicLibrary;
77 use rustc::util::common::{time, ErrorReported};
78 use rustc_trans_utils::trans_crate::TransCrate;
79
80 use serialize::json::ToJson;
81
82 use std::any::Any;
83 use std::cmp::Ordering::Equal;
84 use std::cmp::max;
85 use std::default::Default;
86 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
87 use std::env;
88 use std::ffi::OsString;
89 use std::io::{self, Read, Write};
90 use std::iter::repeat;
91 use std::mem;
92 use std::panic;
93 use std::path::{PathBuf, Path};
94 use std::process::{self, Command, Stdio};
95 use std::rc::Rc;
96 use std::str;
97 use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
98 use std::sync::{Once, ONCE_INIT};
99 use std::thread;
100
101 use syntax::ast;
102 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
103 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
104 use syntax::parse::{self, PResult};
105 use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
106
107 #[cfg(test)]
108 mod test;
109
110 pub mod profile;
111 pub mod driver;
112 pub mod pretty;
113 mod derive_registrar;
114
115 pub mod target_features {
116     use syntax::ast;
117     use syntax::symbol::Symbol;
118     use rustc::session::Session;
119     use rustc_trans_utils::trans_crate::TransCrate;
120
121     /// Add `target_feature = "..."` cfgs for a variety of platform
122     /// specific features (SSE, NEON etc.).
123     ///
124     /// This is performed by checking whether a whitelisted set of
125     /// features is available on the target machine, by querying LLVM.
126     pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session, trans: &TransCrate) {
127         let tf = Symbol::intern("target_feature");
128
129         for feat in trans.target_features(sess) {
130             cfg.insert((tf, Some(feat)));
131         }
132
133         if sess.crt_static_feature() {
134             cfg.insert((tf, Some(Symbol::intern("crt-static"))));
135         }
136     }
137 }
138
139 const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
140                                       md#bug-reports";
141
142 const ICE_REPORT_COMPILER_FLAGS: &'static [&'static str] = &[
143     "Z",
144     "C",
145     "crate-type",
146 ];
147 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &'static [&'static str] = &[
148     "metadata",
149     "extra-filename",
150 ];
151 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &'static [&'static str] = &[
152     "incremental",
153 ];
154
155 pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
156     match result {
157         Err(CompileIncomplete::Errored(ErrorReported)) => {
158             sess.abort_if_errors();
159             panic!("error reported but abort_if_errors didn't abort???");
160         }
161         Err(CompileIncomplete::Stopped) => {
162             sess.fatal("compilation terminated");
163         }
164         Ok(x) => x,
165     }
166 }
167
168 pub fn run<F>(run_compiler: F) -> isize
169     where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
170 {
171     monitor(move || {
172         let (result, session) = run_compiler();
173         if let Err(CompileIncomplete::Errored(_)) = result {
174             match session {
175                 Some(sess) => {
176                     sess.abort_if_errors();
177                     panic!("error reported but abort_if_errors didn't abort???");
178                 }
179                 None => {
180                     let emitter =
181                         errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
182                                                                None,
183                                                                true,
184                                                                false);
185                     let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
186                     handler.emit(&MultiSpan::new(),
187                                  "aborting due to previous error(s)",
188                                  errors::Level::Fatal);
189                     panic::resume_unwind(Box::new(errors::FatalErrorMarker));
190                 }
191             }
192         }
193     });
194     0
195 }
196
197 fn load_backend_from_dylib(path: &Path) -> fn() -> Box<TransCrate> {
198     // Note that we're specifically using `open_global_now` here rather than
199     // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
200     // where NOW means "bind everything right now" because we don't want
201     // surprises later on and RTLD_GLOBAL allows the symbols to be made
202     // available for future dynamic libraries opened. This is currently used by
203     // loading LLVM and then making its symbols available for other dynamic
204     // libraries.
205     let lib = match DynamicLibrary::open_global_now(path) {
206         Ok(lib) => lib,
207         Err(err) => {
208             let err = format!("couldn't load codegen backend {:?}: {:?}",
209                               path,
210                               err);
211             early_error(ErrorOutputType::default(), &err);
212         }
213     };
214     unsafe {
215         match lib.symbol("__rustc_codegen_backend") {
216             Ok(f) => {
217                 mem::forget(lib);
218                 mem::transmute::<*mut u8, _>(f)
219             }
220             Err(e) => {
221                 let err = format!("couldn't load codegen backend as it \
222                                    doesn't export the `__rustc_codegen_backend` \
223                                    symbol: {:?}", e);
224                 early_error(ErrorOutputType::default(), &err);
225             }
226         }
227     }
228 }
229
230 pub fn get_trans(sess: &Session) -> Box<TransCrate> {
231     static INIT: Once = ONCE_INIT;
232     static mut LOAD: fn() -> Box<TransCrate> = || unreachable!();
233
234     INIT.call_once(|| {
235         let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref()
236             .unwrap_or(&sess.target.target.options.codegen_backend);
237         let backend = match &trans_name[..] {
238             "metadata_only" => {
239                 rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
240             }
241             filename if filename.contains(".") => {
242                 load_backend_from_dylib(filename.as_ref())
243             }
244             trans_name => get_trans_sysroot(trans_name),
245         };
246
247         unsafe {
248             LOAD = backend;
249         }
250     });
251     let backend = unsafe { LOAD() };
252     backend.init(sess);
253     backend
254 }
255
256 fn get_trans_sysroot(backend_name: &str) -> fn() -> Box<TransCrate> {
257     // For now we only allow this function to be called once as it'll dlopen a
258     // few things, which seems to work best if we only do that once. In
259     // general this assertion never trips due to the once guard in `get_trans`,
260     // but there's a few manual calls to this function in this file we protect
261     // against.
262     static LOADED: AtomicBool = ATOMIC_BOOL_INIT;
263     assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
264             "cannot load the default trans backend twice");
265
266     // When we're compiling this library with `--test` it'll run as a binary but
267     // not actually exercise much functionality. As a result most of the logic
268     // here is defunkt (it assumes we're a dynamic library in a sysroot) so
269     // let's just return a dummy creation function which won't be used in
270     // general anyway.
271     if cfg!(test) {
272         return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
273     }
274
275     let target = session::config::host_triple();
276     let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
277     let path = current_dll_path()
278         .and_then(|s| s.canonicalize().ok());
279     if let Some(dll) = path {
280         // use `parent` twice to chop off the file name and then also the
281         // directory containing the dll which should be either `lib` or `bin`.
282         if let Some(path) = dll.parent().and_then(|p| p.parent()) {
283             // The original `path` pointed at the `rustc_driver` crate's dll.
284             // Now that dll should only be in one of two locations. The first is
285             // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
286             // other is the target's libdir, for example
287             // `$sysroot/lib/rustlib/$target/lib/*.dll`.
288             //
289             // We don't know which, so let's assume that if our `path` above
290             // ends in `$target` we *could* be in the target libdir, and always
291             // assume that we may be in the main libdir.
292             sysroot_candidates.push(path.to_owned());
293
294             if path.ends_with(target) {
295                 sysroot_candidates.extend(path.parent() // chop off `$target`
296                     .and_then(|p| p.parent())           // chop off `rustlib`
297                     .and_then(|p| p.parent())           // chop off `lib`
298                     .map(|s| s.to_owned()));
299             }
300         }
301     }
302
303     let sysroot = sysroot_candidates.iter()
304         .map(|sysroot| {
305             let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
306             sysroot.join(libdir).with_file_name("codegen-backends")
307         })
308         .filter(|f| {
309             info!("codegen backend candidate: {}", f.display());
310             f.exists()
311         })
312         .next();
313     let sysroot = match sysroot {
314         Some(path) => path,
315         None => {
316             let candidates = sysroot_candidates.iter()
317                 .map(|p| p.display().to_string())
318                 .collect::<Vec<_>>()
319                 .join("\n* ");
320             let err = format!("failed to find a `codegen-backends` folder \
321                                in the sysroot candidates:\n* {}", candidates);
322             early_error(ErrorOutputType::default(), &err);
323         }
324     };
325     info!("probing {} for a codegen backend", sysroot.display());
326
327     let d = match sysroot.read_dir() {
328         Ok(d) => d,
329         Err(e) => {
330             let err = format!("failed to load default codegen backend, couldn't \
331                                read `{}`: {}", sysroot.display(), e);
332             early_error(ErrorOutputType::default(), &err);
333         }
334     };
335
336     let mut file: Option<PathBuf> = None;
337
338     let expected_name = format!("rustc_trans-{}", backend_name);
339     for entry in d.filter_map(|e| e.ok()) {
340         let path = entry.path();
341         let filename = match path.file_name().and_then(|s| s.to_str()) {
342             Some(s) => s,
343             None => continue,
344         };
345         if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
346             continue
347         }
348         let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
349         if name != expected_name {
350             continue
351         }
352         if let Some(ref prev) = file {
353             let err = format!("duplicate codegen backends found\n\
354                 first:  {}\n\
355                 second: {}\n\
356             ", prev.display(), path.display());
357             early_error(ErrorOutputType::default(), &err);
358         }
359         file = Some(path.clone());
360     }
361
362     match file {
363         Some(ref s) => return load_backend_from_dylib(s),
364         None => {
365             let err = format!("failed to load default codegen backend for `{}`, \
366                                no appropriate codegen dylib found in `{}`",
367                                backend_name, sysroot.display());
368             early_error(ErrorOutputType::default(), &err);
369         }
370     }
371
372     #[cfg(unix)]
373     fn current_dll_path() -> Option<PathBuf> {
374         use std::ffi::{OsStr, CStr};
375         use std::os::unix::prelude::*;
376
377         unsafe {
378             let addr = current_dll_path as usize as *mut _;
379             let mut info = mem::zeroed();
380             if libc::dladdr(addr, &mut info) == 0 {
381                 info!("dladdr failed");
382                 return None
383             }
384             if info.dli_fname.is_null() {
385                 info!("dladdr returned null pointer");
386                 return None
387             }
388             let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
389             let os = OsStr::from_bytes(bytes);
390             Some(PathBuf::from(os))
391         }
392     }
393
394     #[cfg(windows)]
395     fn current_dll_path() -> Option<PathBuf> {
396         use std::ffi::OsString;
397         use std::os::windows::prelude::*;
398
399         extern "system" {
400             fn GetModuleHandleExW(dwFlags: u32,
401                                   lpModuleName: usize,
402                                   phModule: *mut usize) -> i32;
403             fn GetModuleFileNameW(hModule: usize,
404                                   lpFilename: *mut u16,
405                                   nSize: u32) -> u32;
406         }
407
408         const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004;
409
410         unsafe {
411             let mut module = 0;
412             let r = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
413                                        current_dll_path as usize,
414                                        &mut module);
415             if r == 0 {
416                 info!("GetModuleHandleExW failed: {}", io::Error::last_os_error());
417                 return None
418             }
419             let mut space = Vec::with_capacity(1024);
420             let r = GetModuleFileNameW(module,
421                                        space.as_mut_ptr(),
422                                        space.capacity() as u32);
423             if r == 0 {
424                 info!("GetModuleFileNameW failed: {}", io::Error::last_os_error());
425                 return None
426             }
427             let r = r as usize;
428             if r >= space.capacity() {
429                 info!("our buffer was too small? {}",
430                       io::Error::last_os_error());
431                 return None
432             }
433             space.set_len(r);
434             let os = OsString::from_wide(&space);
435             Some(PathBuf::from(os))
436         }
437     }
438 }
439
440 // Parse args and run the compiler. This is the primary entry point for rustc.
441 // See comments on CompilerCalls below for details about the callbacks argument.
442 // The FileLoader provides a way to load files from sources other than the file system.
443 pub fn run_compiler<'a>(args: &[String],
444                         callbacks: &mut CompilerCalls<'a>,
445                         file_loader: Option<Box<FileLoader + 'static>>,
446                         emitter_dest: Option<Box<Write + Send>>)
447                         -> (CompileResult, Option<Session>)
448 {
449     macro_rules! do_or_return {($expr: expr, $sess: expr) => {
450         match $expr {
451             Compilation::Stop => return (Ok(()), $sess),
452             Compilation::Continue => {}
453         }
454     }}
455
456     let matches = match handle_options(args) {
457         Some(matches) => matches,
458         None => return (Ok(()), None),
459     };
460
461     let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
462
463     let descriptions = diagnostics_registry();
464
465     do_or_return!(callbacks.early_callback(&matches,
466                                            &sopts,
467                                            &cfg,
468                                            &descriptions,
469                                            sopts.error_format),
470                                            None);
471
472     let (odir, ofile) = make_output(&matches);
473     let (input, input_file_path, input_err) = match make_input(&matches.free) {
474         Some((input, input_file_path, input_err)) => {
475             let (input, input_file_path) = callbacks.some_input(input, input_file_path);
476             (input, input_file_path, input_err)
477         },
478         None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
479             Some((input, input_file_path)) => (input, input_file_path, None),
480             None => return (Ok(()), None),
481         },
482     };
483
484     let loader = file_loader.unwrap_or(box RealFileLoader);
485     let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
486     let mut sess = session::build_session_with_codemap(
487         sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
488     );
489
490     if let Some(err) = input_err {
491         // Immediately stop compilation if there was an issue reading
492         // the input (for example if the input stream is not UTF-8).
493         sess.err(&format!("{}", err));
494         return (Err(CompileIncomplete::Stopped), Some(sess));
495     }
496
497     let trans = get_trans(&sess);
498
499     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
500
501     let mut cfg = config::build_configuration(&sess, cfg);
502     target_features::add_configuration(&mut cfg, &sess, &*trans);
503     sess.parse_sess.config = cfg;
504
505     let plugins = sess.opts.debugging_opts.extra_plugins.clone();
506
507     let cstore = CStore::new(trans.metadata_loader());
508
509     do_or_return!(callbacks.late_callback(&*trans,
510                                           &matches,
511                                           &sess,
512                                           &cstore,
513                                           &input,
514                                           &odir,
515                                           &ofile), Some(sess));
516
517     let control = callbacks.build_controller(&sess, &matches);
518
519     (driver::compile_input(trans,
520                            &sess,
521                            &cstore,
522                            &input_file_path,
523                            &input,
524                            &odir,
525                            &ofile,
526                            Some(plugins),
527                            &control),
528      Some(sess))
529 }
530
531 // Extract output directory and file from matches.
532 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
533     let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
534     let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
535     (odir, ofile)
536 }
537
538 // Extract input (string or file and optional path) from matches.
539 fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
540     if free_matches.len() == 1 {
541         let ifile = &free_matches[0];
542         if ifile == "-" {
543             let mut src = String::new();
544             let err = if io::stdin().read_to_string(&mut src).is_err() {
545                 Some(io::Error::new(io::ErrorKind::InvalidData,
546                                     "couldn't read from stdin, as it did not contain valid UTF-8"))
547             } else {
548                 None
549             };
550             Some((Input::Str { name: FileName::Anon, input: src },
551                   None, err))
552         } else {
553             Some((Input::File(PathBuf::from(ifile)),
554                   Some(PathBuf::from(ifile)), None))
555         }
556     } else {
557         None
558     }
559 }
560
561 fn parse_pretty(sess: &Session,
562                 matches: &getopts::Matches)
563                 -> Option<(PpMode, Option<UserIdentifiedItem>)> {
564     let pretty = if sess.opts.debugging_opts.unstable_options {
565         matches.opt_default("pretty", "normal").map(|a| {
566             // stable pretty-print variants only
567             pretty::parse_pretty(sess, &a, false)
568         })
569     } else {
570         None
571     };
572
573     if pretty.is_none() {
574         sess.opts.debugging_opts.unpretty.as_ref().map(|a| {
575             // extended with unstable pretty-print variants
576             pretty::parse_pretty(sess, &a, true)
577         })
578     } else {
579         pretty
580     }
581 }
582
583 // Whether to stop or continue compilation.
584 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
585 pub enum Compilation {
586     Stop,
587     Continue,
588 }
589
590 impl Compilation {
591     pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
592         match self {
593             Compilation::Stop => Compilation::Stop,
594             Compilation::Continue => next(),
595         }
596     }
597 }
598
599 // A trait for customising the compilation process. Offers a number of hooks for
600 // executing custom code or customising input.
601 pub trait CompilerCalls<'a> {
602     // Hook for a callback early in the process of handling arguments. This will
603     // be called straight after options have been parsed but before anything
604     // else (e.g., selecting input and output).
605     fn early_callback(&mut self,
606                       _: &getopts::Matches,
607                       _: &config::Options,
608                       _: &ast::CrateConfig,
609                       _: &errors::registry::Registry,
610                       _: ErrorOutputType)
611                       -> Compilation {
612         Compilation::Continue
613     }
614
615     // Hook for a callback late in the process of handling arguments. This will
616     // be called just before actual compilation starts (and before build_controller
617     // is called), after all arguments etc. have been completely handled.
618     fn late_callback(&mut self,
619                      _: &TransCrate,
620                      _: &getopts::Matches,
621                      _: &Session,
622                      _: &CrateStore,
623                      _: &Input,
624                      _: &Option<PathBuf>,
625                      _: &Option<PathBuf>)
626                      -> Compilation {
627         Compilation::Continue
628     }
629
630     // Called after we extract the input from the arguments. Gives the implementer
631     // an opportunity to change the inputs or to add some custom input handling.
632     // The default behaviour is to simply pass through the inputs.
633     fn some_input(&mut self,
634                   input: Input,
635                   input_path: Option<PathBuf>)
636                   -> (Input, Option<PathBuf>) {
637         (input, input_path)
638     }
639
640     // Called after we extract the input from the arguments if there is no valid
641     // input. Gives the implementer an opportunity to supply alternate input (by
642     // returning a Some value) or to add custom behaviour for this error such as
643     // emitting error messages. Returning None will cause compilation to stop
644     // at this point.
645     fn no_input(&mut self,
646                 _: &getopts::Matches,
647                 _: &config::Options,
648                 _: &ast::CrateConfig,
649                 _: &Option<PathBuf>,
650                 _: &Option<PathBuf>,
651                 _: &errors::registry::Registry)
652                 -> Option<(Input, Option<PathBuf>)> {
653         None
654     }
655
656     // Create a CompilController struct for controlling the behaviour of
657     // compilation.
658     fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>;
659 }
660
661 // CompilerCalls instance for a regular rustc build.
662 #[derive(Copy, Clone)]
663 pub struct RustcDefaultCalls;
664
665 // FIXME remove these and use winapi 0.3 instead
666 // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
667 #[cfg(unix)]
668 fn stdout_isatty() -> bool {
669     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
670 }
671
672 #[cfg(windows)]
673 fn stdout_isatty() -> bool {
674     type DWORD = u32;
675     type BOOL = i32;
676     type HANDLE = *mut u8;
677     type LPDWORD = *mut u32;
678     const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
679     extern "system" {
680         fn GetStdHandle(which: DWORD) -> HANDLE;
681         fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
682     }
683     unsafe {
684         let handle = GetStdHandle(STD_OUTPUT_HANDLE);
685         let mut out = 0;
686         GetConsoleMode(handle, &mut out) != 0
687     }
688 }
689
690 fn handle_explain(code: &str,
691                   descriptions: &errors::registry::Registry,
692                   output: ErrorOutputType) {
693     let normalised = if code.starts_with("E") {
694         code.to_string()
695     } else {
696         format!("E{0:0>4}", code)
697     };
698     match descriptions.find_description(&normalised) {
699         Some(ref description) => {
700             let mut is_in_code_block = false;
701             let mut text = String::new();
702
703             // Slice off the leading newline and print.
704             for line in description[1..].lines() {
705                 let indent_level = line.find(|c: char| !c.is_whitespace())
706                     .unwrap_or_else(|| line.len());
707                 let dedented_line = &line[indent_level..];
708                 if dedented_line.starts_with("```") {
709                     is_in_code_block = !is_in_code_block;
710                     text.push_str(&line[..(indent_level+3)]);
711                 } else if is_in_code_block && dedented_line.starts_with("# ") {
712                     continue;
713                 } else {
714                     text.push_str(line);
715                 }
716                 text.push('\n');
717             }
718
719             if stdout_isatty() {
720                 show_content_with_pager(&text);
721             } else {
722                 print!("{}", text);
723             }
724         }
725         None => {
726             early_error(output, &format!("no extended information for {}", code));
727         }
728     }
729 }
730
731 fn show_content_with_pager(content: &String) {
732     let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) {
733         OsString::from("more.com")
734     } else {
735         OsString::from("less")
736     });
737
738     let mut fallback_to_println = false;
739
740     match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
741         Ok(mut pager) => {
742             if let Some(pipe) = pager.stdin.as_mut() {
743                 if pipe.write_all(content.as_bytes()).is_err() {
744                     fallback_to_println = true;
745                 }
746             }
747
748             if pager.wait().is_err() {
749                 fallback_to_println = true;
750             }
751         }
752         Err(_) => {
753             fallback_to_println = true;
754         }
755     }
756
757     // If pager fails for whatever reason, we should still print the content
758     // to standard output
759     if fallback_to_println {
760         print!("{}", content);
761     }
762 }
763
764 impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
765     fn early_callback(&mut self,
766                       matches: &getopts::Matches,
767                       _: &config::Options,
768                       _: &ast::CrateConfig,
769                       descriptions: &errors::registry::Registry,
770                       output: ErrorOutputType)
771                       -> Compilation {
772         if let Some(ref code) = matches.opt_str("explain") {
773             handle_explain(code, descriptions, output);
774             return Compilation::Stop;
775         }
776
777         Compilation::Continue
778     }
779
780     fn no_input(&mut self,
781                 matches: &getopts::Matches,
782                 sopts: &config::Options,
783                 cfg: &ast::CrateConfig,
784                 odir: &Option<PathBuf>,
785                 ofile: &Option<PathBuf>,
786                 descriptions: &errors::registry::Registry)
787                 -> Option<(Input, Option<PathBuf>)> {
788         match matches.free.len() {
789             0 => {
790                 let mut sess = build_session(sopts.clone(),
791                     None,
792                     descriptions.clone());
793                 if sopts.describe_lints {
794                     let mut ls = lint::LintStore::new();
795                     rustc_lint::register_builtins(&mut ls, Some(&sess));
796                     describe_lints(&sess, &ls, false);
797                     return None;
798                 }
799                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
800                 let mut cfg = config::build_configuration(&sess, cfg.clone());
801                 let trans = get_trans(&sess);
802                 target_features::add_configuration(&mut cfg, &sess, &*trans);
803                 sess.parse_sess.config = cfg;
804                 let should_stop = RustcDefaultCalls::print_crate_info(
805                     &*trans,
806                     &sess,
807                     None,
808                     odir,
809                     ofile
810                 );
811
812                 if should_stop == Compilation::Stop {
813                     return None;
814                 }
815                 early_error(sopts.error_format, "no input filename given");
816             }
817             1 => panic!("make_input should have provided valid inputs"),
818             _ => early_error(sopts.error_format, "multiple input filenames provided"),
819         }
820     }
821
822     fn late_callback(&mut self,
823                      trans: &TransCrate,
824                      matches: &getopts::Matches,
825                      sess: &Session,
826                      cstore: &CrateStore,
827                      input: &Input,
828                      odir: &Option<PathBuf>,
829                      ofile: &Option<PathBuf>)
830                      -> Compilation {
831         RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile)
832             .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
833     }
834
835     fn build_controller(&mut self,
836                         sess: &Session,
837                         matches: &getopts::Matches)
838                         -> CompileController<'a> {
839         let mut control = CompileController::basic();
840
841         control.keep_ast = sess.opts.debugging_opts.keep_ast;
842         control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error;
843
844         if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
845             if ppm.needs_ast_map(&opt_uii) {
846                 control.after_hir_lowering.stop = Compilation::Stop;
847
848                 control.after_parse.callback = box move |state| {
849                     state.krate = Some(pretty::fold_crate(state.session,
850                                                           state.krate.take().unwrap(),
851                                                           ppm));
852                 };
853                 control.after_hir_lowering.callback = box move |state| {
854                     pretty::print_after_hir_lowering(state.session,
855                                                      state.cstore.unwrap(),
856                                                      state.hir_map.unwrap(),
857                                                      state.analysis.unwrap(),
858                                                      state.resolutions.unwrap(),
859                                                      state.input,
860                                                      &state.expanded_crate.take().unwrap(),
861                                                      state.crate_name.unwrap(),
862                                                      ppm,
863                                                      state.arenas.unwrap(),
864                                                      state.output_filenames.unwrap(),
865                                                      opt_uii.clone(),
866                                                      state.out_file);
867                 };
868             } else {
869                 control.after_parse.stop = Compilation::Stop;
870
871                 control.after_parse.callback = box move |state| {
872                     let krate = pretty::fold_crate(state.session, state.krate.take().unwrap(), ppm);
873                     pretty::print_after_parsing(state.session,
874                                                 state.input,
875                                                 &krate,
876                                                 ppm,
877                                                 state.out_file);
878                 };
879             }
880
881             return control;
882         }
883
884         if sess.opts.debugging_opts.parse_only ||
885            sess.opts.debugging_opts.show_span.is_some() ||
886            sess.opts.debugging_opts.ast_json_noexpand {
887             control.after_parse.stop = Compilation::Stop;
888         }
889
890         if sess.opts.debugging_opts.no_analysis ||
891            sess.opts.debugging_opts.ast_json {
892             control.after_hir_lowering.stop = Compilation::Stop;
893         }
894
895         if sess.opts.debugging_opts.save_analysis {
896             enable_save_analysis(&mut control);
897         }
898
899         if sess.print_fuel_crate.is_some() {
900             let old_callback = control.compilation_done.callback;
901             control.compilation_done.callback = box move |state| {
902                 old_callback(state);
903                 let sess = state.session;
904                 println!("Fuel used by {}: {}",
905                     sess.print_fuel_crate.as_ref().unwrap(),
906                     sess.print_fuel.get());
907             }
908         }
909         control
910     }
911 }
912
913 pub fn enable_save_analysis(control: &mut CompileController) {
914     control.keep_ast = true;
915     control.after_analysis.callback = box |state| {
916         time(state.session.time_passes(), "save analysis", || {
917             save::process_crate(state.tcx.unwrap(),
918                                 state.expanded_crate.unwrap(),
919                                 state.analysis.unwrap(),
920                                 state.crate_name.unwrap(),
921                                 None,
922                                 DumpHandler::new(state.out_dir,
923                                                  state.crate_name.unwrap()))
924         });
925     };
926     control.after_analysis.run_callback_on_error = true;
927     control.make_glob_map = resolve::MakeGlobMap::Yes;
928 }
929
930 impl RustcDefaultCalls {
931     pub fn list_metadata(sess: &Session,
932                          cstore: &CrateStore,
933                          matches: &getopts::Matches,
934                          input: &Input)
935                          -> Compilation {
936         let r = matches.opt_strs("Z");
937         if r.contains(&("ls".to_string())) {
938             match input {
939                 &Input::File(ref ifile) => {
940                     let path = &(*ifile);
941                     let mut v = Vec::new();
942                     locator::list_file_metadata(&sess.target.target,
943                                                 path,
944                                                 cstore.metadata_loader(),
945                                                 &mut v)
946                             .unwrap();
947                     println!("{}", String::from_utf8(v).unwrap());
948                 }
949                 &Input::Str { .. } => {
950                     early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
951                 }
952             }
953             return Compilation::Stop;
954         }
955
956         return Compilation::Continue;
957     }
958
959
960     fn print_crate_info(trans: &TransCrate,
961                         sess: &Session,
962                         input: Option<&Input>,
963                         odir: &Option<PathBuf>,
964                         ofile: &Option<PathBuf>)
965                         -> Compilation {
966         use rustc::session::config::PrintRequest::*;
967         // PrintRequest::NativeStaticLibs is special - printed during linking
968         // (empty iterator returns true)
969         if sess.opts.prints.iter().all(|&p| p==PrintRequest::NativeStaticLibs) {
970             return Compilation::Continue;
971         }
972
973         let attrs = match input {
974             None => None,
975             Some(input) => {
976                 let result = parse_crate_attrs(sess, input);
977                 match result {
978                     Ok(attrs) => Some(attrs),
979                     Err(mut parse_error) => {
980                         parse_error.emit();
981                         return Compilation::Stop;
982                     }
983                 }
984             }
985         };
986         for req in &sess.opts.prints {
987             match *req {
988                 TargetList => {
989                     let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
990                     targets.sort();
991                     println!("{}", targets.join("\n"));
992                 },
993                 Sysroot => println!("{}", sess.sysroot().display()),
994                 TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
995                 FileNames | CrateName => {
996                     let input = match input {
997                         Some(input) => input,
998                         None => early_error(ErrorOutputType::default(), "no input file provided"),
999                     };
1000                     let attrs = attrs.as_ref().unwrap();
1001                     let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
1002                     let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input);
1003                     if *req == PrintRequest::CrateName {
1004                         println!("{}", id);
1005                         continue;
1006                     }
1007                     let crate_types = driver::collect_crate_types(sess, attrs);
1008                     for &style in &crate_types {
1009                         let fname = rustc_trans_utils::link::filename_for_input(
1010                             sess,
1011                             style,
1012                             &id,
1013                             &t_outputs
1014                         );
1015                         println!("{}",
1016                                  fname.file_name()
1017                                       .unwrap()
1018                                       .to_string_lossy());
1019                     }
1020                 }
1021                 Cfg => {
1022                     let allow_unstable_cfg = UnstableFeatures::from_environment()
1023                         .is_nightly_build();
1024
1025                     let mut cfgs = Vec::new();
1026                     for &(name, ref value) in sess.parse_sess.config.iter() {
1027                         let gated_cfg = GatedCfg::gate(&ast::MetaItem {
1028                             name,
1029                             node: ast::MetaItemKind::Word,
1030                             span: DUMMY_SP,
1031                         });
1032
1033                         // Note that crt-static is a specially recognized cfg
1034                         // directive that's printed out here as part of
1035                         // rust-lang/rust#37406, but in general the
1036                         // `target_feature` cfg is gated under
1037                         // rust-lang/rust#29717. For now this is just
1038                         // specifically allowing the crt-static cfg and that's
1039                         // it, this is intended to get into Cargo and then go
1040                         // through to build scripts.
1041                         let value = value.as_ref().map(|s| s.as_str());
1042                         let value = value.as_ref().map(|s| s.as_ref());
1043                         if name != "target_feature" || value != Some("crt-static") {
1044                             if !allow_unstable_cfg && gated_cfg.is_some() {
1045                                 continue;
1046                             }
1047                         }
1048
1049                         cfgs.push(if let Some(value) = value {
1050                             format!("{}=\"{}\"", name, value)
1051                         } else {
1052                             format!("{}", name)
1053                         });
1054                     }
1055
1056                     cfgs.sort();
1057                     for cfg in cfgs {
1058                         println!("{}", cfg);
1059                     }
1060                 }
1061                 RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
1062                     trans.print(*req, sess);
1063                 }
1064                 // Any output here interferes with Cargo's parsing of other printed output
1065                 PrintRequest::NativeStaticLibs => {}
1066             }
1067         }
1068         return Compilation::Stop;
1069     }
1070 }
1071
1072 /// Returns a version string such as "0.12.0-dev".
1073 fn release_str() -> Option<&'static str> {
1074     option_env!("CFG_RELEASE")
1075 }
1076
1077 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
1078 fn commit_hash_str() -> Option<&'static str> {
1079     option_env!("CFG_VER_HASH")
1080 }
1081
1082 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
1083 fn commit_date_str() -> Option<&'static str> {
1084     option_env!("CFG_VER_DATE")
1085 }
1086
1087 /// Prints version information
1088 pub fn version(binary: &str, matches: &getopts::Matches) {
1089     let verbose = matches.opt_present("verbose");
1090
1091     println!("{} {}",
1092              binary,
1093              option_env!("CFG_VERSION").unwrap_or("unknown version"));
1094     if verbose {
1095         fn unw(x: Option<&str>) -> &str {
1096             x.unwrap_or("unknown")
1097         }
1098         println!("binary: {}", binary);
1099         println!("commit-hash: {}", unw(commit_hash_str()));
1100         println!("commit-date: {}", unw(commit_date_str()));
1101         println!("host: {}", config::host_triple());
1102         println!("release: {}", unw(release_str()));
1103         get_trans_sysroot("llvm")().print_version();
1104     }
1105 }
1106
1107 fn usage(verbose: bool, include_unstable_options: bool) {
1108     let groups = if verbose {
1109         config::rustc_optgroups()
1110     } else {
1111         config::rustc_short_optgroups()
1112     };
1113     let mut options = getopts::Options::new();
1114     for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
1115         (option.apply)(&mut options);
1116     }
1117     let message = format!("Usage: rustc [OPTIONS] INPUT");
1118     let nightly_help = if nightly_options::is_nightly_build() {
1119         "\n    -Z help             Print internal options for debugging rustc"
1120     } else {
1121         ""
1122     };
1123     let verbose_help = if verbose {
1124         ""
1125     } else {
1126         "\n    --help -v           Print the full set of options rustc accepts"
1127     };
1128     println!("{}\nAdditional help:
1129     -C help             Print codegen options
1130     -W help             \
1131               Print 'lint' options and default settings{}{}\n",
1132              options.usage(&message),
1133              nightly_help,
1134              verbose_help);
1135 }
1136
1137 fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
1138     println!("
1139 Available lint options:
1140     -W <foo>           Warn about <foo>
1141     -A <foo>           \
1142               Allow <foo>
1143     -D <foo>           Deny <foo>
1144     -F <foo>           Forbid <foo> \
1145               (deny <foo> and all attempts to override)
1146
1147 ");
1148
1149     fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
1150         let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
1151         lints.sort_by(|x: &&Lint, y: &&Lint| {
1152             match x.default_level(sess).cmp(&y.default_level(sess)) {
1153                 // The sort doesn't case-fold but it's doubtful we care.
1154                 Equal => x.name.cmp(y.name),
1155                 r => r,
1156             }
1157         });
1158         lints
1159     }
1160
1161     fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
1162                         -> Vec<(&'static str, Vec<lint::LintId>)> {
1163         let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
1164         lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
1165                        &(y, _): &(&'static str, Vec<lint::LintId>)| {
1166             x.cmp(y)
1167         });
1168         lints
1169     }
1170
1171     let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints()
1172                                                    .iter()
1173                                                    .cloned()
1174                                                    .partition(|&(_, p)| p);
1175     let plugin = sort_lints(sess, plugin);
1176     let builtin = sort_lints(sess, builtin);
1177
1178     let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
1179                                                                  .iter()
1180                                                                  .cloned()
1181                                                                  .partition(|&(.., p)| p);
1182     let plugin_groups = sort_lint_groups(plugin_groups);
1183     let builtin_groups = sort_lint_groups(builtin_groups);
1184
1185     let max_name_len = plugin.iter()
1186                              .chain(&builtin)
1187                              .map(|&s| s.name.chars().count())
1188                              .max()
1189                              .unwrap_or(0);
1190     let padded = |x: &str| {
1191         let mut s = repeat(" ")
1192                         .take(max_name_len - x.chars().count())
1193                         .collect::<String>();
1194         s.push_str(x);
1195         s
1196     };
1197
1198     println!("Lint checks provided by rustc:\n");
1199     println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
1200     println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
1201
1202     let print_lints = |lints: Vec<&Lint>| {
1203         for lint in lints {
1204             let name = lint.name_lower().replace("_", "-");
1205             println!("    {}  {:7.7}  {}",
1206                      padded(&name),
1207                      lint.default_level.as_str(),
1208                      lint.desc);
1209         }
1210         println!("\n");
1211     };
1212
1213     print_lints(builtin);
1214
1215
1216
1217     let max_name_len = max("warnings".len(),
1218                            plugin_groups.iter()
1219                                         .chain(&builtin_groups)
1220                                         .map(|&(s, _)| s.chars().count())
1221                                         .max()
1222                                         .unwrap_or(0));
1223
1224     let padded = |x: &str| {
1225         let mut s = repeat(" ")
1226                         .take(max_name_len - x.chars().count())
1227                         .collect::<String>();
1228         s.push_str(x);
1229         s
1230     };
1231
1232     println!("Lint groups provided by rustc:\n");
1233     println!("    {}  {}", padded("name"), "sub-lints");
1234     println!("    {}  {}", padded("----"), "---------");
1235     println!("    {}  {}", padded("warnings"), "all lints that are set to issue warnings");
1236
1237     let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
1238         for (name, to) in lints {
1239             let name = name.to_lowercase().replace("_", "-");
1240             let desc = to.into_iter()
1241                          .map(|x| x.to_string().replace("_", "-"))
1242                          .collect::<Vec<String>>()
1243                          .join(", ");
1244             println!("    {}  {}", padded(&name), desc);
1245         }
1246         println!("\n");
1247     };
1248
1249     print_lint_groups(builtin_groups);
1250
1251     match (loaded_plugins, plugin.len(), plugin_groups.len()) {
1252         (false, 0, _) | (false, _, 0) => {
1253             println!("Compiler plugins can provide additional lints and lint groups. To see a \
1254                       listing of these, re-run `rustc -W help` with a crate filename.");
1255         }
1256         (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
1257         (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
1258         (true, l, g) => {
1259             if l > 0 {
1260                 println!("Lint checks provided by plugins loaded by this crate:\n");
1261                 print_lints(plugin);
1262             }
1263             if g > 0 {
1264                 println!("Lint groups provided by plugins loaded by this crate:\n");
1265                 print_lint_groups(plugin_groups);
1266             }
1267         }
1268     }
1269 }
1270
1271 fn describe_debug_flags() {
1272     println!("\nAvailable debug options:\n");
1273     print_flag_list("-Z", config::DB_OPTIONS);
1274 }
1275
1276 fn describe_codegen_flags() {
1277     println!("\nAvailable codegen options:\n");
1278     print_flag_list("-C", config::CG_OPTIONS);
1279 }
1280
1281 fn print_flag_list<T>(cmdline_opt: &str,
1282                       flag_list: &[(&'static str, T, Option<&'static str>, &'static str)]) {
1283     let max_len = flag_list.iter()
1284                            .map(|&(name, _, opt_type_desc, _)| {
1285                                let extra_len = match opt_type_desc {
1286                                    Some(..) => 4,
1287                                    None => 0,
1288                                };
1289                                name.chars().count() + extra_len
1290                            })
1291                            .max()
1292                            .unwrap_or(0);
1293
1294     for &(name, _, opt_type_desc, desc) in flag_list {
1295         let (width, extra) = match opt_type_desc {
1296             Some(..) => (max_len - 4, "=val"),
1297             None => (max_len, ""),
1298         };
1299         println!("    {} {:>width$}{} -- {}",
1300                  cmdline_opt,
1301                  name.replace("_", "-"),
1302                  extra,
1303                  desc,
1304                  width = width);
1305     }
1306 }
1307
1308 /// Process command line options. Emits messages as appropriate. If compilation
1309 /// should continue, returns a getopts::Matches object parsed from args,
1310 /// otherwise returns None.
1311 ///
1312 /// The compiler's handling of options is a little complicated as it ties into
1313 /// our stability story, and it's even *more* complicated by historical
1314 /// accidents. The current intention of each compiler option is to have one of
1315 /// three modes:
1316 ///
1317 /// 1. An option is stable and can be used everywhere.
1318 /// 2. An option is unstable, but was historically allowed on the stable
1319 ///    channel.
1320 /// 3. An option is unstable, and can only be used on nightly.
1321 ///
1322 /// Like unstable library and language features, however, unstable options have
1323 /// always required a form of "opt in" to indicate that you're using them. This
1324 /// provides the easy ability to scan a code base to check to see if anything
1325 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
1326 ///
1327 /// All options behind `-Z` are considered unstable by default. Other top-level
1328 /// options can also be considered unstable, and they were unlocked through the
1329 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
1330 /// instability in both cases, though.
1331 ///
1332 /// So with all that in mind, the comments below have some more detail about the
1333 /// contortions done here to get things to work out correctly.
1334 pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
1335     // Throw away the first argument, the name of the binary
1336     let args = &args[1..];
1337
1338     if args.is_empty() {
1339         // user did not write `-v` nor `-Z unstable-options`, so do not
1340         // include that extra information.
1341         usage(false, false);
1342         return None;
1343     }
1344
1345     // Parse with *all* options defined in the compiler, we don't worry about
1346     // option stability here we just want to parse as much as possible.
1347     let mut options = getopts::Options::new();
1348     for option in config::rustc_optgroups() {
1349         (option.apply)(&mut options);
1350     }
1351     let matches = match options.parse(args) {
1352         Ok(m) => m,
1353         Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
1354     };
1355
1356     // For all options we just parsed, we check a few aspects:
1357     //
1358     // * If the option is stable, we're all good
1359     // * If the option wasn't passed, we're all good
1360     // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1361     //   ourselves), then we require the `-Z unstable-options` flag to unlock
1362     //   this option that was passed.
1363     // * If we're a nightly compiler, then unstable options are now unlocked, so
1364     //   we're good to go.
1365     // * Otherwise, if we're a truly unstable option then we generate an error
1366     //   (unstable option being used on stable)
1367     // * If we're a historically stable-but-should-be-unstable option then we
1368     //   emit a warning that we're going to turn this into an error soon.
1369     nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
1370
1371     if matches.opt_present("h") || matches.opt_present("help") {
1372         // Only show unstable options in --help if we *really* accept unstable
1373         // options, which catches the case where we got `-Z unstable-options` on
1374         // the stable channel of Rust which was accidentally allowed
1375         // historically.
1376         usage(matches.opt_present("verbose"),
1377               nightly_options::is_unstable_enabled(&matches));
1378         return None;
1379     }
1380
1381     // Don't handle -W help here, because we might first load plugins.
1382     let r = matches.opt_strs("Z");
1383     if r.iter().any(|x| *x == "help") {
1384         describe_debug_flags();
1385         return None;
1386     }
1387
1388     let cg_flags = matches.opt_strs("C");
1389     if cg_flags.iter().any(|x| *x == "help") {
1390         describe_codegen_flags();
1391         return None;
1392     }
1393
1394     if cg_flags.iter().any(|x| *x == "no-stack-check") {
1395         early_warn(ErrorOutputType::default(),
1396                    "the --no-stack-check flag is deprecated and does nothing");
1397     }
1398
1399     if cg_flags.contains(&"passes=list".to_string()) {
1400         get_trans_sysroot("llvm")().print_passes();
1401         return None;
1402     }
1403
1404     if matches.opt_present("version") {
1405         version("rustc", &matches);
1406         return None;
1407     }
1408
1409     Some(matches)
1410 }
1411
1412 fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
1413     match *input {
1414         Input::File(ref ifile) => {
1415             parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess)
1416         }
1417         Input::Str { ref name, ref input } => {
1418             parse::parse_crate_attrs_from_source_str(name.clone(),
1419                                                      input.clone(),
1420                                                      &sess.parse_sess)
1421         }
1422     }
1423 }
1424
1425 /// Runs `f` in a suitable thread for running `rustc`; returns a
1426 /// `Result` with either the return value of `f` or -- if a panic
1427 /// occurs -- the panic value.
1428 pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>>
1429     where F: FnOnce() -> R + Send + 'static,
1430           R: Send + 'static,
1431 {
1432     // Temporarily have stack size set to 16MB to deal with nom-using crates failing
1433     const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
1434
1435     let mut cfg = thread::Builder::new().name("rustc".to_string());
1436
1437     // FIXME: Hacks on hacks. If the env is trying to override the stack size
1438     // then *don't* set it explicitly.
1439     if env::var_os("RUST_MIN_STACK").is_none() {
1440         cfg = cfg.stack_size(STACK_SIZE);
1441     }
1442
1443     let thread = cfg.spawn(f);
1444     thread.unwrap().join()
1445 }
1446
1447 /// Get a list of extra command-line flags provided by the user, as strings.
1448 ///
1449 /// This function is used during ICEs to show more information useful for
1450 /// debugging, since some ICEs only happens with non-default compiler flags
1451 /// (and the users don't always report them).
1452 fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
1453     let mut args = Vec::new();
1454     for arg in env::args_os() {
1455         args.push(arg.to_string_lossy().to_string());
1456     }
1457
1458     let matches = if let Some(matches) = handle_options(&args) {
1459         matches
1460     } else {
1461         return None;
1462     };
1463
1464     let mut result = Vec::new();
1465     let mut excluded_cargo_defaults = false;
1466     for flag in ICE_REPORT_COMPILER_FLAGS {
1467         let prefix = if flag.len() == 1 { "-" } else { "--" };
1468
1469         for content in &matches.opt_strs(flag) {
1470             // Split always returns the first element
1471             let name = if let Some(first) = content.split('=').next() {
1472                 first
1473             } else {
1474                 &content
1475             };
1476
1477             let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
1478                 name
1479             } else {
1480                 content
1481             };
1482
1483             if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
1484                 result.push(format!("{}{} {}", prefix, flag, content));
1485             } else {
1486                 excluded_cargo_defaults = true;
1487             }
1488         }
1489     }
1490
1491     if result.len() > 0 {
1492         Some((result, excluded_cargo_defaults))
1493     } else {
1494         None
1495     }
1496 }
1497
1498 /// Run a procedure which will detect panics in the compiler and print nicer
1499 /// error messages rather than just failing the test.
1500 ///
1501 /// The diagnostic emitter yielded to the procedure should be used for reporting
1502 /// errors of the compiler.
1503 pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
1504     let result = in_rustc_thread(move || {
1505         f()
1506     });
1507
1508     if let Err(value) = result {
1509         // Thread panicked without emitting a fatal diagnostic
1510         if !value.is::<errors::FatalErrorMarker>() {
1511             // Emit a newline
1512             eprintln!("");
1513
1514             let emitter =
1515                 Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
1516                                                                 None,
1517                                                                 false,
1518                                                                 false));
1519             let handler = errors::Handler::with_emitter(true, false, emitter);
1520
1521             // a .span_bug or .bug call has already printed what
1522             // it wants to print.
1523             if !value.is::<errors::ExplicitBug>() {
1524                 handler.emit(&MultiSpan::new(),
1525                              "unexpected panic",
1526                              errors::Level::Bug);
1527             }
1528
1529             let mut xs = vec![
1530                 "the compiler unexpectedly panicked. this is a bug.".to_string(),
1531                 format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
1532                 format!("rustc {} running on {}",
1533                         option_env!("CFG_VERSION").unwrap_or("unknown_version"),
1534                         config::host_triple()),
1535             ];
1536
1537             if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
1538                 xs.push(format!("compiler flags: {}", flags.join(" ")));
1539
1540                 if excluded_cargo_defaults {
1541                     xs.push("some of the compiler flags provided by cargo are hidden".to_string());
1542                 }
1543             }
1544
1545             for note in &xs {
1546                 handler.emit(&MultiSpan::new(),
1547                              &note,
1548                              errors::Level::Note);
1549             }
1550         }
1551
1552         panic::resume_unwind(Box::new(errors::FatalErrorMarker));
1553     }
1554 }
1555
1556 pub fn diagnostics_registry() -> errors::registry::Registry {
1557     use errors::registry::Registry;
1558
1559     let mut all_errors = Vec::new();
1560     all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
1561     all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
1562     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
1563     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
1564     // FIXME: need to figure out a way to get these back in here
1565     // all_errors.extend_from_slice(get_trans(sess).diagnostics());
1566     all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
1567     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
1568     all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
1569     all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
1570     all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
1571     all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS);
1572     all_errors.extend_from_slice(&syntax::DIAGNOSTICS);
1573
1574     Registry::new(&all_errors)
1575 }
1576
1577 pub fn main() {
1578     env_logger::init().unwrap();
1579     let result = run(|| {
1580         let args = env::args_os().enumerate()
1581             .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
1582                 early_error(ErrorOutputType::default(),
1583                             &format!("Argument {} is not valid Unicode: {:?}", i, arg))
1584             }))
1585             .collect::<Vec<_>>();
1586         run_compiler(&args,
1587                      &mut RustcDefaultCalls,
1588                      None,
1589                      None)
1590     });
1591     process::exit(result as i32);
1592 }