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