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