]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/lib.rs
Auto merge of #35856 - phimuemue:master, r=brson
[rust.git] / src / librustc_driver / lib.rs
1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The Rust compiler.
12 //!
13 //! # Note
14 //!
15 //! This API is completely unstable and subject to change.
16
17 #![crate_name = "rustc_driver"]
18 #![unstable(feature = "rustc_private", issue = "27812")]
19 #![crate_type = "dylib"]
20 #![crate_type = "rlib"]
21 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
22       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
23       html_root_url = "https://doc.rust-lang.org/nightly/")]
24 #![cfg_attr(not(stage0), deny(warnings))]
25
26 #![feature(box_syntax)]
27 #![feature(libc)]
28 #![feature(quote)]
29 #![feature(rustc_diagnostic_macros)]
30 #![feature(rustc_private)]
31 #![feature(set_stdio)]
32 #![feature(staged_api)]
33 #![feature(question_mark)]
34
35 extern crate arena;
36 extern crate flate;
37 extern crate getopts;
38 extern crate graphviz;
39 extern crate libc;
40 extern crate rustc;
41 extern crate rustc_back;
42 extern crate rustc_borrowck;
43 extern crate rustc_const_eval;
44 extern crate rustc_errors as errors;
45 extern crate rustc_passes;
46 extern crate rustc_lint;
47 extern crate rustc_plugin;
48 extern crate rustc_privacy;
49 extern crate rustc_incremental;
50 extern crate rustc_metadata;
51 extern crate rustc_mir;
52 extern crate rustc_resolve;
53 extern crate rustc_save_analysis;
54 extern crate rustc_trans;
55 extern crate rustc_typeck;
56 extern crate serialize;
57 extern crate rustc_llvm as llvm;
58 #[macro_use]
59 extern crate log;
60 #[macro_use]
61 extern crate syntax;
62 extern crate syntax_ext;
63 extern crate syntax_pos;
64
65 use driver::CompileController;
66 use pretty::{PpMode, UserIdentifiedItem};
67
68 use rustc_resolve as resolve;
69 use rustc_save_analysis as save;
70 use rustc_trans::back::link;
71 use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
72 use rustc::dep_graph::DepGraph;
73 use rustc::session::{self, config, Session, build_session, CompileResult};
74 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
75 use rustc::session::config::{get_unstable_features_setting, nightly_options};
76 use rustc::lint::Lint;
77 use rustc::lint;
78 use rustc_metadata::loader;
79 use rustc_metadata::cstore::CStore;
80 use rustc::util::common::time;
81
82 use std::cmp::max;
83 use std::cmp::Ordering::Equal;
84 use std::default::Default;
85 use std::env;
86 use std::io::{self, Read, Write};
87 use std::iter::repeat;
88 use std::path::PathBuf;
89 use std::process;
90 use std::rc::Rc;
91 use std::str;
92 use std::sync::{Arc, Mutex};
93 use std::thread;
94
95 use rustc::session::early_error;
96
97 use syntax::{ast, json};
98 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
99 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
100 use syntax::parse::{self, PResult};
101 use syntax_pos::MultiSpan;
102 use errors::emitter::Emitter;
103
104 #[cfg(test)]
105 pub mod test;
106
107 pub mod driver;
108 pub mod pretty;
109 pub mod target_features;
110
111
112 const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
113                                       md#bug-reports";
114
115 #[inline]
116 fn abort_msg(err_count: usize) -> String {
117     match err_count {
118         0 => "aborting with no errors (maybe a bug?)".to_owned(),
119         1 => "aborting due to previous error".to_owned(),
120         e => format!("aborting due to {} previous errors", e),
121     }
122 }
123
124 pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
125     match result {
126         Err(err_count) => {
127             sess.fatal(&abort_msg(err_count));
128         }
129         Ok(x) => x,
130     }
131 }
132
133 pub fn run(args: Vec<String>) -> isize {
134     monitor(move || {
135         let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
136         if let Err(err_count) = result {
137             if err_count > 0 {
138                 match session {
139                     Some(sess) => sess.fatal(&abort_msg(err_count)),
140                     None => {
141                         let emitter =
142                             errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
143                                                                    None);
144                         let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
145                         handler.emit(&MultiSpan::new(),
146                                      &abort_msg(err_count),
147                                      errors::Level::Fatal);
148                         exit_on_err();
149                     }
150                 }
151             }
152         }
153     });
154     0
155 }
156
157 pub fn run_compiler<'a>(args: &[String],
158                         callbacks: &mut CompilerCalls<'a>)
159                         -> (CompileResult, Option<Session>) {
160     run_compiler_with_file_loader(args, callbacks, box RealFileLoader)
161 }
162
163 // Parse args and run the compiler. This is the primary entry point for rustc.
164 // See comments on CompilerCalls below for details about the callbacks argument.
165 // The FileLoader provides a way to load files from sources other than the file system.
166 pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
167                                             callbacks: &mut CompilerCalls<'a>,
168                                             loader: Box<L>)
169                                             -> (CompileResult, Option<Session>)
170     where L: FileLoader + 'static {
171     macro_rules! do_or_return {($expr: expr, $sess: expr) => {
172         match $expr {
173             Compilation::Stop => return (Ok(()), $sess),
174             Compilation::Continue => {}
175         }
176     }}
177
178     let matches = match handle_options(args) {
179         Some(matches) => matches,
180         None => return (Ok(()), None),
181     };
182
183     let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
184
185     if sopts.debugging_opts.debug_llvm {
186         unsafe { llvm::LLVMRustSetDebug(1); }
187     }
188
189     let descriptions = diagnostics_registry();
190
191     do_or_return!(callbacks.early_callback(&matches,
192                                            &sopts,
193                                            &cfg,
194                                            &descriptions,
195                                            sopts.error_format),
196                                            None);
197
198     let (odir, ofile) = make_output(&matches);
199     let (input, input_file_path) = match make_input(&matches.free) {
200         Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
201         None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
202             Some((input, input_file_path)) => (input, input_file_path),
203             None => return (Ok(()), None),
204         },
205     };
206
207     let dep_graph = DepGraph::new(sopts.build_dep_graph());
208     let cstore = Rc::new(CStore::new(&dep_graph));
209     let codemap = Rc::new(CodeMap::with_file_loader(loader));
210     let sess = session::build_session_with_codemap(sopts,
211                                                    &dep_graph,
212                                                    input_file_path,
213                                                    descriptions,
214                                                    cstore.clone(),
215                                                    codemap);
216     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
217     let mut cfg = config::build_configuration(&sess, cfg);
218     target_features::add_configuration(&mut cfg, &sess);
219
220     do_or_return!(callbacks.late_callback(&matches, &sess, &cfg, &input, &odir, &ofile),
221                   Some(sess));
222
223     let plugins = sess.opts.debugging_opts.extra_plugins.clone();
224     let control = callbacks.build_controller(&sess, &matches);
225     (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile,
226                            Some(plugins), &control),
227      Some(sess))
228 }
229
230 // Extract output directory and file from matches.
231 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
232     let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
233     let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
234     (odir, ofile)
235 }
236
237 // Extract input (string or file and optional path) from matches.
238 fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
239     if free_matches.len() == 1 {
240         let ifile = &free_matches[0][..];
241         if ifile == "-" {
242             let mut src = String::new();
243             io::stdin().read_to_string(&mut src).unwrap();
244             Some((Input::Str { name: driver::anon_src(), input: src },
245                   None))
246         } else {
247             Some((Input::File(PathBuf::from(ifile)),
248                   Some(PathBuf::from(ifile))))
249         }
250     } else {
251         None
252     }
253 }
254
255 fn parse_pretty(sess: &Session,
256                 matches: &getopts::Matches)
257                 -> Option<(PpMode, Option<UserIdentifiedItem>)> {
258     let pretty = if sess.opts.debugging_opts.unstable_options {
259         matches.opt_default("pretty", "normal").map(|a| {
260             // stable pretty-print variants only
261             pretty::parse_pretty(sess, &a, false)
262         })
263     } else {
264         None
265     };
266     if pretty.is_none() && sess.unstable_options() {
267         matches.opt_str("unpretty").map(|a| {
268             // extended with unstable pretty-print variants
269             pretty::parse_pretty(sess, &a, true)
270         })
271     } else {
272         pretty
273     }
274 }
275
276 // Whether to stop or continue compilation.
277 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
278 pub enum Compilation {
279     Stop,
280     Continue,
281 }
282
283 impl Compilation {
284     pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
285         match self {
286             Compilation::Stop => Compilation::Stop,
287             Compilation::Continue => next(),
288         }
289     }
290 }
291
292 // A trait for customising the compilation process. Offers a number of hooks for
293 // executing custom code or customising input.
294 pub trait CompilerCalls<'a> {
295     // Hook for a callback early in the process of handling arguments. This will
296     // be called straight after options have been parsed but before anything
297     // else (e.g., selecting input and output).
298     fn early_callback(&mut self,
299                       _: &getopts::Matches,
300                       _: &config::Options,
301                       _: &ast::CrateConfig,
302                       _: &errors::registry::Registry,
303                       _: ErrorOutputType)
304                       -> Compilation {
305         Compilation::Continue
306     }
307
308     // Hook for a callback late in the process of handling arguments. This will
309     // be called just before actual compilation starts (and before build_controller
310     // is called), after all arguments etc. have been completely handled.
311     fn late_callback(&mut self,
312                      _: &getopts::Matches,
313                      _: &Session,
314                      _: &ast::CrateConfig,
315                      _: &Input,
316                      _: &Option<PathBuf>,
317                      _: &Option<PathBuf>)
318                      -> Compilation {
319         Compilation::Continue
320     }
321
322     // Called after we extract the input from the arguments. Gives the implementer
323     // an opportunity to change the inputs or to add some custom input handling.
324     // The default behaviour is to simply pass through the inputs.
325     fn some_input(&mut self,
326                   input: Input,
327                   input_path: Option<PathBuf>)
328                   -> (Input, Option<PathBuf>) {
329         (input, input_path)
330     }
331
332     // Called after we extract the input from the arguments if there is no valid
333     // input. Gives the implementer an opportunity to supply alternate input (by
334     // returning a Some value) or to add custom behaviour for this error such as
335     // emitting error messages. Returning None will cause compilation to stop
336     // at this point.
337     fn no_input(&mut self,
338                 _: &getopts::Matches,
339                 _: &config::Options,
340                 _: &ast::CrateConfig,
341                 _: &Option<PathBuf>,
342                 _: &Option<PathBuf>,
343                 _: &errors::registry::Registry)
344                 -> Option<(Input, Option<PathBuf>)> {
345         None
346     }
347
348     // Create a CompilController struct for controlling the behaviour of
349     // compilation.
350     fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>;
351 }
352
353 // CompilerCalls instance for a regular rustc build.
354 #[derive(Copy, Clone)]
355 pub struct RustcDefaultCalls;
356
357 fn handle_explain(code: &str,
358                   descriptions: &errors::registry::Registry,
359                   output: ErrorOutputType) {
360     let normalised = if code.starts_with("E") {
361         code.to_string()
362     } else {
363         format!("E{0:0>4}", code)
364     };
365     match descriptions.find_description(&normalised) {
366         Some(ref description) => {
367             // Slice off the leading newline and print.
368             print!("{}", &(&description[1..]).split("\n").map(|x| {
369                 format!("{}\n", if x.starts_with("```") {
370                     "```"
371                 } else {
372                     x
373                 })
374             }).collect::<String>());
375         }
376         None => {
377             early_error(output, &format!("no extended information for {}", code));
378         }
379     }
380 }
381
382 fn check_cfg(cfg: &ast::CrateConfig,
383              output: ErrorOutputType) {
384     let emitter: Box<Emitter> = match output {
385         config::ErrorOutputType::HumanReadable(color_config) => {
386             Box::new(errors::emitter::EmitterWriter::stderr(color_config, None))
387         }
388         config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()),
389     };
390     let handler = errors::Handler::with_emitter(true, false, emitter);
391
392     let mut saw_invalid_predicate = false;
393     for item in cfg.iter() {
394         if item.is_meta_item_list() {
395             saw_invalid_predicate = true;
396             handler.emit(&MultiSpan::new(),
397                          &format!("invalid predicate in --cfg command line argument: `{}`",
398                                   item.name()),
399                             errors::Level::Fatal);
400         }
401     }
402
403     if saw_invalid_predicate {
404         panic!(errors::FatalError);
405     }
406 }
407
408 impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
409     fn early_callback(&mut self,
410                       matches: &getopts::Matches,
411                       _: &config::Options,
412                       cfg: &ast::CrateConfig,
413                       descriptions: &errors::registry::Registry,
414                       output: ErrorOutputType)
415                       -> Compilation {
416         if let Some(ref code) = matches.opt_str("explain") {
417             handle_explain(code, descriptions, output);
418             return Compilation::Stop;
419         }
420
421         check_cfg(cfg, output);
422         Compilation::Continue
423     }
424
425     fn no_input(&mut self,
426                 matches: &getopts::Matches,
427                 sopts: &config::Options,
428                 cfg: &ast::CrateConfig,
429                 odir: &Option<PathBuf>,
430                 ofile: &Option<PathBuf>,
431                 descriptions: &errors::registry::Registry)
432                 -> Option<(Input, Option<PathBuf>)> {
433         match matches.free.len() {
434             0 => {
435                 if sopts.describe_lints {
436                     let mut ls = lint::LintStore::new();
437                     rustc_lint::register_builtins(&mut ls, None);
438                     describe_lints(&ls, false);
439                     return None;
440                 }
441                 let dep_graph = DepGraph::new(sopts.build_dep_graph());
442                 let cstore = Rc::new(CStore::new(&dep_graph));
443                 let sess = build_session(sopts.clone(),
444                     &dep_graph,
445                     None,
446                     descriptions.clone(),
447                     cstore.clone());
448                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
449                 let mut cfg = config::build_configuration(&sess, cfg.clone());
450                 target_features::add_configuration(&mut cfg, &sess);
451                 let should_stop = RustcDefaultCalls::print_crate_info(&sess,
452                                                                       &cfg,
453                                                                       None,
454                                                                       odir,
455                                                                       ofile);
456                 if should_stop == Compilation::Stop {
457                     return None;
458                 }
459                 early_error(sopts.error_format, "no input filename given");
460             }
461             1 => panic!("make_input should have provided valid inputs"),
462             _ => early_error(sopts.error_format, "multiple input filenames provided"),
463         }
464
465         None
466     }
467
468     fn late_callback(&mut self,
469                      matches: &getopts::Matches,
470                      sess: &Session,
471                      cfg: &ast::CrateConfig,
472                      input: &Input,
473                      odir: &Option<PathBuf>,
474                      ofile: &Option<PathBuf>)
475                      -> Compilation {
476         RustcDefaultCalls::print_crate_info(sess, cfg, Some(input), odir, ofile)
477             .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input))
478     }
479
480     fn build_controller(&mut self,
481                         sess: &Session,
482                         matches: &getopts::Matches)
483                         -> CompileController<'a> {
484         let mut control = CompileController::basic();
485
486         if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
487             if ppm.needs_ast_map(&opt_uii) {
488                 control.after_hir_lowering.stop = Compilation::Stop;
489
490                 control.after_parse.callback = box move |state| {
491                     state.krate = Some(pretty::fold_crate(state.krate.take().unwrap(), ppm));
492                 };
493                 control.after_hir_lowering.callback = box move |state| {
494                     pretty::print_after_hir_lowering(state.session,
495                                                      state.ast_map.unwrap(),
496                                                      state.analysis.unwrap(),
497                                                      state.resolutions.unwrap(),
498                                                      state.input,
499                                                      &state.expanded_crate.take().unwrap(),
500                                                      state.crate_name.unwrap(),
501                                                      ppm,
502                                                      state.arenas.unwrap(),
503                                                      opt_uii.clone(),
504                                                      state.out_file);
505                 };
506             } else {
507                 control.after_parse.stop = Compilation::Stop;
508
509                 control.after_parse.callback = box move |state| {
510                     let krate = pretty::fold_crate(state.krate.take().unwrap(), ppm);
511                     pretty::print_after_parsing(state.session,
512                                                 state.input,
513                                                 &krate,
514                                                 ppm,
515                                                 state.out_file);
516                 };
517             }
518
519             return control;
520         }
521
522         if sess.opts.debugging_opts.parse_only ||
523            sess.opts.debugging_opts.show_span.is_some() ||
524            sess.opts.debugging_opts.ast_json_noexpand {
525             control.after_parse.stop = Compilation::Stop;
526         }
527
528         if sess.opts.debugging_opts.no_analysis ||
529            sess.opts.debugging_opts.ast_json {
530             control.after_hir_lowering.stop = Compilation::Stop;
531         }
532
533         if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
534             control.after_llvm.stop = Compilation::Stop;
535         }
536
537         if save_analysis(sess) {
538             control.after_analysis.callback = box |state| {
539                 time(state.session.time_passes(), "save analysis", || {
540                     save::process_crate(state.tcx.unwrap(),
541                                         state.expanded_crate.unwrap(),
542                                         state.analysis.unwrap(),
543                                         state.crate_name.unwrap(),
544                                         state.out_dir,
545                                         save_analysis_format(state.session))
546                 });
547             };
548             control.after_analysis.run_callback_on_error = true;
549             control.make_glob_map = resolve::MakeGlobMap::Yes;
550         }
551
552         control
553     }
554 }
555
556 fn save_analysis(sess: &Session) -> bool {
557     sess.opts.debugging_opts.save_analysis ||
558     sess.opts.debugging_opts.save_analysis_csv
559 }
560
561 fn save_analysis_format(sess: &Session) -> save::Format {
562     if sess.opts.debugging_opts.save_analysis {
563         save::Format::Json
564     } else if sess.opts.debugging_opts.save_analysis_csv {
565         save::Format::Csv
566     } else {
567         unreachable!();
568     }
569 }
570
571 impl RustcDefaultCalls {
572     pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input) -> Compilation {
573         let r = matches.opt_strs("Z");
574         if r.contains(&("ls".to_string())) {
575             match input {
576                 &Input::File(ref ifile) => {
577                     let path = &(*ifile);
578                     let mut v = Vec::new();
579                     loader::list_file_metadata(&sess.target.target, path, &mut v)
580                         .unwrap();
581                     println!("{}", String::from_utf8(v).unwrap());
582                 }
583                 &Input::Str { .. } => {
584                     early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
585                 }
586             }
587             return Compilation::Stop;
588         }
589
590         return Compilation::Continue;
591     }
592
593
594     fn print_crate_info(sess: &Session,
595                         cfg: &ast::CrateConfig,
596                         input: Option<&Input>,
597                         odir: &Option<PathBuf>,
598                         ofile: &Option<PathBuf>)
599                         -> Compilation {
600         if sess.opts.prints.is_empty() {
601             return Compilation::Continue;
602         }
603
604         let attrs = match input {
605             None => None,
606             Some(input) => {
607                 let result = parse_crate_attrs(sess, input);
608                 match result {
609                     Ok(attrs) => Some(attrs),
610                     Err(mut parse_error) => {
611                         parse_error.emit();
612                         return Compilation::Stop;
613                     }
614                 }
615             }
616         };
617         for req in &sess.opts.prints {
618             match *req {
619                 PrintRequest::TargetList => {
620                     let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
621                     targets.sort();
622                     println!("{}", targets.join("\n"));
623                 },
624                 PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
625                 PrintRequest::FileNames |
626                 PrintRequest::CrateName => {
627                     let input = match input {
628                         Some(input) => input,
629                         None => early_error(ErrorOutputType::default(), "no input file provided"),
630                     };
631                     let attrs = attrs.as_ref().unwrap();
632                     let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
633                     let id = link::find_crate_name(Some(sess), attrs, input);
634                     if *req == PrintRequest::CrateName {
635                         println!("{}", id);
636                         continue;
637                     }
638                     let crate_types = driver::collect_crate_types(sess, attrs);
639                     for &style in &crate_types {
640                         let fname = link::filename_for_input(sess, style, &id, &t_outputs);
641                         println!("{}",
642                                  fname.file_name()
643                                       .unwrap()
644                                       .to_string_lossy());
645                     }
646                 }
647                 PrintRequest::Cfg => {
648                     let allow_unstable_cfg = match get_unstable_features_setting() {
649                         UnstableFeatures::Disallow => false,
650                         _ => true,
651                     };
652
653                     for cfg in cfg {
654                         if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
655                             continue;
656                         }
657
658                         if cfg.is_word() {
659                             println!("{}", cfg.name());
660                         } else if let Some(s) = cfg.value_str() {
661                             println!("{}=\"{}\"", cfg.name(), s);
662                         } else if cfg.is_meta_item_list() {
663                             // Right now there are not and should not be any
664                             // MetaItemKind::List items in the configuration returned by
665                             // `build_configuration`.
666                             panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name())
667                         } else {
668                             // There also shouldn't be literals.
669                             panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name())
670                         }
671                     }
672                 }
673                 PrintRequest::TargetCPUs => {
674                     let tm = create_target_machine(sess);
675                     unsafe { llvm::LLVMRustPrintTargetCPUs(tm); }
676                 }
677                 PrintRequest::TargetFeatures => {
678                     let tm = create_target_machine(sess);
679                     unsafe { llvm::LLVMRustPrintTargetFeatures(tm); }
680                 }
681                 PrintRequest::RelocationModels => {
682                     println!("Available relocation models:");
683                     for &(name, _) in RELOC_MODEL_ARGS.iter() {
684                         println!("    {}", name);
685                     }
686                     println!("");
687                 }
688                 PrintRequest::CodeModels => {
689                     println!("Available code models:");
690                     for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){
691                         println!("    {}", name);
692                     }
693                     println!("");
694                 }
695             }
696         }
697         return Compilation::Stop;
698     }
699 }
700
701 /// Returns a version string such as "0.12.0-dev".
702 pub fn release_str() -> Option<&'static str> {
703     option_env!("CFG_RELEASE")
704 }
705
706 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
707 pub fn commit_hash_str() -> Option<&'static str> {
708     option_env!("CFG_VER_HASH")
709 }
710
711 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
712 pub fn commit_date_str() -> Option<&'static str> {
713     option_env!("CFG_VER_DATE")
714 }
715
716 /// Prints version information
717 pub fn version(binary: &str, matches: &getopts::Matches) {
718     let verbose = matches.opt_present("verbose");
719
720     println!("{} {}",
721              binary,
722              option_env!("CFG_VERSION").unwrap_or("unknown version"));
723     if verbose {
724         fn unw(x: Option<&str>) -> &str {
725             x.unwrap_or("unknown")
726         }
727         println!("binary: {}", binary);
728         println!("commit-hash: {}", unw(commit_hash_str()));
729         println!("commit-date: {}", unw(commit_date_str()));
730         println!("host: {}", config::host_triple());
731         println!("release: {}", unw(release_str()));
732     }
733 }
734
735 fn usage(verbose: bool, include_unstable_options: bool) {
736     let groups = if verbose {
737         config::rustc_optgroups()
738     } else {
739         config::rustc_short_optgroups()
740     };
741     let groups: Vec<_> = groups.into_iter()
742                                .filter(|x| include_unstable_options || x.is_stable())
743                                .map(|x| x.opt_group)
744                                .collect();
745     let message = format!("Usage: rustc [OPTIONS] INPUT");
746     let extra_help = if verbose {
747         ""
748     } else {
749         "\n    --help -v           Print the full set of options rustc accepts"
750     };
751     println!("{}\nAdditional help:
752     -C help             Print codegen options
753     -W help             \
754               Print 'lint' options and default settings
755     -Z help             Print internal \
756               options for debugging rustc{}\n",
757              getopts::usage(&message, &groups),
758              extra_help);
759 }
760
761 fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
762     println!("
763 Available lint options:
764     -W <foo>           Warn about <foo>
765     -A <foo>           \
766               Allow <foo>
767     -D <foo>           Deny <foo>
768     -F <foo>           Forbid <foo> \
769               (deny, and deny all overrides)
770
771 ");
772
773     fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
774         let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
775         lints.sort_by(|x: &&Lint, y: &&Lint| {
776             match x.default_level.cmp(&y.default_level) {
777                 // The sort doesn't case-fold but it's doubtful we care.
778                 Equal => x.name.cmp(y.name),
779                 r => r,
780             }
781         });
782         lints
783     }
784
785     fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
786                         -> Vec<(&'static str, Vec<lint::LintId>)> {
787         let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
788         lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
789                        &(y, _): &(&'static str, Vec<lint::LintId>)| {
790             x.cmp(y)
791         });
792         lints
793     }
794
795     let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints()
796                                                    .iter()
797                                                    .cloned()
798                                                    .partition(|&(_, p)| p);
799     let plugin = sort_lints(plugin);
800     let builtin = sort_lints(builtin);
801
802     let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
803                                                                  .iter()
804                                                                  .cloned()
805                                                                  .partition(|&(_, _, p)| p);
806     let plugin_groups = sort_lint_groups(plugin_groups);
807     let builtin_groups = sort_lint_groups(builtin_groups);
808
809     let max_name_len = plugin.iter()
810                              .chain(&builtin)
811                              .map(|&s| s.name.chars().count())
812                              .max()
813                              .unwrap_or(0);
814     let padded = |x: &str| {
815         let mut s = repeat(" ")
816                         .take(max_name_len - x.chars().count())
817                         .collect::<String>();
818         s.push_str(x);
819         s
820     };
821
822     println!("Lint checks provided by rustc:\n");
823     println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
824     println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
825
826     let print_lints = |lints: Vec<&Lint>| {
827         for lint in lints {
828             let name = lint.name_lower().replace("_", "-");
829             println!("    {}  {:7.7}  {}",
830                      padded(&name[..]),
831                      lint.default_level.as_str(),
832                      lint.desc);
833         }
834         println!("\n");
835     };
836
837     print_lints(builtin);
838
839
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(" ")
850                         .take(max_name_len - x.chars().count())
851                         .collect::<String>();
852         s.push_str(x);
853         s
854     };
855
856     println!("Lint groups provided by rustc:\n");
857     println!("    {}  {}", padded("name"), "sub-lints");
858     println!("    {}  {}", padded("----"), "---------");
859     println!("    {}  {}", padded("warnings"), "all built-in lints");
860
861     let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
862         for (name, to) in lints {
863             let name = name.to_lowercase().replace("_", "-");
864             let desc = to.into_iter()
865                          .map(|x| x.to_string().replace("_", "-"))
866                          .collect::<Vec<String>>()
867                          .join(", ");
868             println!("    {}  {}", padded(&name[..]), desc);
869         }
870         println!("\n");
871     };
872
873     print_lint_groups(builtin_groups);
874
875     match (loaded_plugins, plugin.len(), plugin_groups.len()) {
876         (false, 0, _) | (false, _, 0) => {
877             println!("Compiler plugins can provide additional lints and lint groups. To see a \
878                       listing of these, re-run `rustc -W help` with a crate filename.");
879         }
880         (false, _, _) => panic!("didn't load lint plugins but got them anyway!"),
881         (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
882         (true, l, g) => {
883             if l > 0 {
884                 println!("Lint checks provided by plugins loaded by this crate:\n");
885                 print_lints(plugin);
886             }
887             if g > 0 {
888                 println!("Lint groups provided by plugins loaded by this crate:\n");
889                 print_lint_groups(plugin_groups);
890             }
891         }
892     }
893 }
894
895 fn describe_debug_flags() {
896     println!("\nAvailable debug options:\n");
897     print_flag_list("-Z", config::DB_OPTIONS);
898 }
899
900 fn describe_codegen_flags() {
901     println!("\nAvailable codegen options:\n");
902     print_flag_list("-C", config::CG_OPTIONS);
903 }
904
905 fn print_flag_list<T>(cmdline_opt: &str,
906                       flag_list: &[(&'static str, T, Option<&'static str>, &'static str)]) {
907     let max_len = flag_list.iter()
908                            .map(|&(name, _, opt_type_desc, _)| {
909                                let extra_len = match opt_type_desc {
910                                    Some(..) => 4,
911                                    None => 0,
912                                };
913                                name.chars().count() + extra_len
914                            })
915                            .max()
916                            .unwrap_or(0);
917
918     for &(name, _, opt_type_desc, desc) in flag_list {
919         let (width, extra) = match opt_type_desc {
920             Some(..) => (max_len - 4, "=val"),
921             None => (max_len, ""),
922         };
923         println!("    {} {:>width$}{} -- {}",
924                  cmdline_opt,
925                  name.replace("_", "-"),
926                  extra,
927                  desc,
928                  width = width);
929     }
930 }
931
932 /// Process command line options. Emits messages as appropriate. If compilation
933 /// should continue, returns a getopts::Matches object parsed from args,
934 /// otherwise returns None.
935 ///
936 /// The compiler's handling of options is a little complication as it ties into
937 /// our stability story, and it's even *more* complicated by historical
938 /// accidents. The current intention of each compiler option is to have one of
939 /// three modes:
940 ///
941 /// 1. An option is stable and can be used everywhere.
942 /// 2. An option is unstable, but was historically allowed on the stable
943 ///    channel.
944 /// 3. An option is unstable, and can only be used on nightly.
945 ///
946 /// Like unstable library and language features, however, unstable options have
947 /// always required a form of "opt in" to indicate that you're using them. This
948 /// provides the easy ability to scan a code base to check to see if anything
949 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
950 ///
951 /// All options behind `-Z` are considered unstable by default. Other top-level
952 /// options can also be considered unstable, and they were unlocked through the
953 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
954 /// instability in both cases, though.
955 ///
956 /// So with all that in mind, the comments below have some more detail about the
957 /// contortions done here to get things to work out correctly.
958 pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
959     // Throw away the first argument, the name of the binary
960     let args = &args[1..];
961
962     if args.is_empty() {
963         // user did not write `-v` nor `-Z unstable-options`, so do not
964         // include that extra information.
965         usage(false, false);
966         return None;
967     }
968
969     // Parse with *all* options defined in the compiler, we don't worry about
970     // option stability here we just want to parse as much as possible.
971     let all_groups: Vec<getopts::OptGroup> = config::rustc_optgroups()
972                                                  .into_iter()
973                                                  .map(|x| x.opt_group)
974                                                  .collect();
975     let matches = match getopts::getopts(&args[..], &all_groups) {
976         Ok(m) => m,
977         Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
978     };
979
980     // For all options we just parsed, we check a few aspects:
981     //
982     // * If the option is stable, we're all good
983     // * If the option wasn't passed, we're all good
984     // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
985     //   ourselves), then we require the `-Z unstable-options` flag to unlock
986     //   this option that was passed.
987     // * If we're a nightly compiler, then unstable options are now unlocked, so
988     //   we're good to go.
989     // * Otherwise, if we're a truly unstable option then we generate an error
990     //   (unstable option being used on stable)
991     // * If we're a historically stable-but-should-be-unstable option then we
992     //   emit a warning that we're going to turn this into an error soon.
993     nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
994
995     if matches.opt_present("h") || matches.opt_present("help") {
996         // Only show unstable options in --help if we *really* accept unstable
997         // options, which catches the case where we got `-Z unstable-options` on
998         // the stable channel of Rust which was accidentally allowed
999         // historically.
1000         usage(matches.opt_present("verbose"),
1001               nightly_options::is_unstable_enabled(&matches));
1002         return None;
1003     }
1004
1005     // Don't handle -W help here, because we might first load plugins.
1006     let r = matches.opt_strs("Z");
1007     if r.iter().any(|x| *x == "help") {
1008         describe_debug_flags();
1009         return None;
1010     }
1011
1012     let cg_flags = matches.opt_strs("C");
1013     if cg_flags.iter().any(|x| *x == "help") {
1014         describe_codegen_flags();
1015         return None;
1016     }
1017
1018     if cg_flags.contains(&"passes=list".to_string()) {
1019         unsafe {
1020             ::llvm::LLVMRustPrintPasses();
1021         }
1022         return None;
1023     }
1024
1025     if matches.opt_present("version") {
1026         version("rustc", &matches);
1027         return None;
1028     }
1029
1030     Some(matches)
1031 }
1032
1033 fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
1034     match *input {
1035         Input::File(ref ifile) => {
1036             parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess)
1037         }
1038         Input::Str { ref name, ref input } => {
1039             parse::parse_crate_attrs_from_source_str(name.clone(),
1040                                                      input.clone(),
1041                                                      Vec::new(),
1042                                                      &sess.parse_sess)
1043         }
1044     }
1045 }
1046
1047 /// Run a procedure which will detect panics in the compiler and print nicer
1048 /// error messages rather than just failing the test.
1049 ///
1050 /// The diagnostic emitter yielded to the procedure should be used for reporting
1051 /// errors of the compiler.
1052 pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
1053     const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB
1054
1055     struct Sink(Arc<Mutex<Vec<u8>>>);
1056     impl Write for Sink {
1057         fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1058             Write::write(&mut *self.0.lock().unwrap(), data)
1059         }
1060         fn flush(&mut self) -> io::Result<()> {
1061             Ok(())
1062         }
1063     }
1064
1065     let data = Arc::new(Mutex::new(Vec::new()));
1066     let err = Sink(data.clone());
1067
1068     let mut cfg = thread::Builder::new().name("rustc".to_string());
1069
1070     // FIXME: Hacks on hacks. If the env is trying to override the stack size
1071     // then *don't* set it explicitly.
1072     if env::var_os("RUST_MIN_STACK").is_none() {
1073         cfg = cfg.stack_size(STACK_SIZE);
1074     }
1075
1076     let thread = cfg.spawn(move || {
1077          io::set_panic(box err);
1078          f()
1079      });
1080
1081      if let Err(value) = thread.unwrap().join() {
1082         // Thread panicked without emitting a fatal diagnostic
1083         if !value.is::<errors::FatalError>() {
1084             let emitter =
1085                 Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None));
1086             let handler = errors::Handler::with_emitter(true, false, emitter);
1087
1088             // a .span_bug or .bug call has already printed what
1089             // it wants to print.
1090             if !value.is::<errors::ExplicitBug>() {
1091                 handler.emit(&MultiSpan::new(),
1092                              "unexpected panic",
1093                              errors::Level::Bug);
1094             }
1095
1096             let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
1097                       format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
1098             for note in &xs {
1099                 handler.emit(&MultiSpan::new(),
1100                              &note[..],
1101                              errors::Level::Note);
1102             }
1103             if match env::var_os("RUST_BACKTRACE") {
1104                 Some(val) => &val != "0",
1105                 None => false,
1106             } {
1107                 handler.emit(&MultiSpan::new(),
1108                              "run with `RUST_BACKTRACE=1` for a backtrace",
1109                              errors::Level::Note);
1110             }
1111
1112             println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
1113         }
1114
1115         exit_on_err();
1116     }
1117 }
1118
1119 fn exit_on_err() -> ! {
1120     // Panic so the process returns a failure code, but don't pollute the
1121     // output with some unnecessary panic messages, we've already
1122     // printed everything that we needed to.
1123     io::set_panic(box io::sink());
1124     panic!();
1125 }
1126
1127 pub fn diagnostics_registry() -> errors::registry::Registry {
1128     use errors::registry::Registry;
1129
1130     let mut all_errors = Vec::new();
1131     all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
1132     all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
1133     all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
1134     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
1135     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
1136     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
1137     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
1138
1139     Registry::new(&all_errors)
1140 }
1141
1142 pub fn main() {
1143     let result = run(env::args().collect());
1144     process::exit(result as i32);
1145 }