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