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