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.
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.
11 //! The Rust compiler.
15 //! This API is completely unstable and subject to change.
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))]
26 #![feature(box_syntax)]
29 #![feature(rustc_diagnostic_macros)]
30 #![feature(rustc_private)]
31 #![feature(set_stdio)]
32 #![feature(staged_api)]
33 #![feature(question_mark)]
38 extern crate graphviz
;
41 extern crate rustc_back
;
42 extern crate rustc_borrowck
;
43 extern crate rustc_const_eval
;
44 extern crate rustc_passes
;
45 extern crate rustc_lint
;
46 extern crate rustc_plugin
;
47 extern crate rustc_privacy
;
48 extern crate rustc_incremental
;
49 extern crate rustc_metadata
;
50 extern crate rustc_mir
;
51 extern crate rustc_resolve
;
52 extern crate rustc_save_analysis
;
53 extern crate rustc_trans
;
54 extern crate rustc_typeck
;
55 extern crate serialize
;
56 extern crate rustc_llvm
as llvm
;
61 extern crate syntax_ext
;
63 use driver
::CompileController
;
64 use pretty
::{PpMode, UserIdentifiedItem}
;
66 use rustc_resolve
as resolve
;
67 use rustc_save_analysis
as save
;
68 use rustc_trans
::back
::link
;
69 use rustc
::session
::{config, Session, build_session, CompileResult}
;
70 use rustc
::session
::config
::{Input, PrintRequest, OutputType, ErrorOutputType}
;
71 use rustc
::session
::config
::{get_unstable_features_setting, nightly_options}
;
72 use rustc
::middle
::cstore
::CrateStore
;
73 use rustc
::lint
::Lint
;
75 use rustc_metadata
::loader
;
76 use rustc_metadata
::cstore
::CStore
;
77 use rustc
::util
::common
::time
;
80 use std
::cmp
::Ordering
::Equal
;
81 use std
::default::Default
;
83 use std
::io
::{self, Read, Write}
;
84 use std
::iter
::repeat
;
85 use std
::path
::PathBuf
;
89 use std
::sync
::{Arc, Mutex}
;
92 use rustc
::session
::early_error
;
95 use syntax
::parse
::{self, PResult}
;
97 use syntax
::errors
::emitter
::Emitter
;
98 use syntax
::diagnostics
;
99 use syntax
::parse
::token
;
100 use syntax
::feature_gate
::{GatedCfg, UnstableFeatures}
;
107 pub mod target_features
;
110 const BUG_REPORT_URL
: &'
static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
114 fn abort_msg(err_count
: usize) -> String
{
116 0 => "aborting with no errors (maybe a bug?)".to_owned(),
117 1 => "aborting due to previous error".to_owned(),
118 e
=> format
!("aborting due to {} previous errors", e
),
122 pub fn abort_on_err
<T
>(result
: Result
<T
, usize>, sess
: &Session
) -> T
{
125 sess
.fatal(&abort_msg(err_count
));
131 pub fn run(args
: Vec
<String
>) -> isize {
133 let (result
, session
) = run_compiler(&args
, &mut RustcDefaultCalls
);
134 if let Err(err_count
) = result
{
137 Some(sess
) => sess
.fatal(&abort_msg(err_count
)),
140 errors
::emitter
::BasicEmitter
::stderr(errors
::ColorConfig
::Auto
);
141 emitter
.emit(None
, &abort_msg(err_count
), None
, errors
::Level
::Fatal
);
151 // Parse args and run the compiler. This is the primary entry point for rustc.
152 // See comments on CompilerCalls below for details about the callbacks argument.
153 pub fn run_compiler
<'a
>(args
: &[String
],
154 callbacks
: &mut CompilerCalls
<'a
>)
155 -> (CompileResult
, Option
<Session
>) {
156 macro_rules
! do_or_return
{($expr
: expr
, $sess
: expr
) => {
158 Compilation
::Stop
=> return (Ok(()), $sess
),
159 Compilation
::Continue
=> {}
163 let matches
= match handle_options(args
) {
164 Some(matches
) => matches
,
165 None
=> return (Ok(()), None
),
168 let sopts
= config
::build_session_options(&matches
);
170 if sopts
.debugging_opts
.debug_llvm
{
171 unsafe { llvm::LLVMSetDebug(1); }
174 let descriptions
= diagnostics_registry();
176 do_or_return
!(callbacks
.early_callback(&matches
,
182 let (odir
, ofile
) = make_output(&matches
);
183 let (input
, input_file_path
) = match make_input(&matches
.free
) {
184 Some((input
, input_file_path
)) => callbacks
.some_input(input
, input_file_path
),
185 None
=> match callbacks
.no_input(&matches
, &sopts
, &odir
, &ofile
, &descriptions
) {
186 Some((input
, input_file_path
)) => (input
, input_file_path
),
187 None
=> return (Ok(()), None
),
191 let cstore
= Rc
::new(CStore
::new(token
::get_ident_interner()));
192 let sess
= build_session(sopts
, input_file_path
, descriptions
, cstore
.clone());
193 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
194 let mut cfg
= config
::build_configuration(&sess
);
195 target_features
::add_configuration(&mut cfg
, &sess
);
197 do_or_return
!(callbacks
.late_callback(&matches
, &sess
, &input
, &odir
, &ofile
), Some(sess
));
199 // It is somewhat unfortunate that this is hardwired in - this is forced by
200 // the fact that pretty_print_input requires the session by value.
201 let pretty
= callbacks
.parse_pretty(&sess
, &matches
);
203 Some((ppm
, opt_uii
)) => {
204 pretty
::pretty_print_input(sess
, &cstore
, cfg
, &input
, ppm
, opt_uii
, ofile
);
205 return (Ok(()), None
);
212 let plugins
= sess
.opts
.debugging_opts
.extra_plugins
.clone();
213 let control
= callbacks
.build_controller(&sess
);
214 (driver
::compile_input(&sess
, &cstore
, cfg
, &input
, &odir
, &ofile
,
215 Some(plugins
), &control
),
219 // Extract output directory and file from matches.
220 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
221 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
222 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
226 // Extract input (string or file and optional path) from matches.
227 fn make_input(free_matches
: &[String
]) -> Option
<(Input
, Option
<PathBuf
>)> {
228 if free_matches
.len() == 1 {
229 let ifile
= &free_matches
[0][..];
231 let mut src
= String
::new();
232 io
::stdin().read_to_string(&mut src
).unwrap();
233 Some((Input
::Str { name: driver::anon_src(), input: src }
,
236 Some((Input
::File(PathBuf
::from(ifile
)),
237 Some(PathBuf
::from(ifile
))))
244 // Whether to stop or continue compilation.
245 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
246 pub enum Compilation
{
252 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
254 Compilation
::Stop
=> Compilation
::Stop
,
255 Compilation
::Continue
=> next(),
260 // A trait for customising the compilation process. Offers a number of hooks for
261 // executing custom code or customising input.
262 pub trait CompilerCalls
<'a
> {
263 // Hook for a callback early in the process of handling arguments. This will
264 // be called straight after options have been parsed but before anything
265 // else (e.g., selecting input and output).
266 fn early_callback(&mut self,
267 _
: &getopts
::Matches
,
269 _
: &diagnostics
::registry
::Registry
,
272 Compilation
::Continue
275 // Hook for a callback late in the process of handling arguments. This will
276 // be called just before actual compilation starts (and before build_controller
277 // is called), after all arguments etc. have been completely handled.
278 fn late_callback(&mut self,
279 _
: &getopts
::Matches
,
285 Compilation
::Continue
288 // Called after we extract the input from the arguments. Gives the implementer
289 // an opportunity to change the inputs or to add some custom input handling.
290 // The default behaviour is to simply pass through the inputs.
291 fn some_input(&mut self,
293 input_path
: Option
<PathBuf
>)
294 -> (Input
, Option
<PathBuf
>) {
298 // Called after we extract the input from the arguments if there is no valid
299 // input. Gives the implementer an opportunity to supply alternate input (by
300 // returning a Some value) or to add custom behaviour for this error such as
301 // emitting error messages. Returning None will cause compilation to stop
303 fn no_input(&mut self,
304 _
: &getopts
::Matches
,
308 _
: &diagnostics
::registry
::Registry
)
309 -> Option
<(Input
, Option
<PathBuf
>)> {
313 // Parse pretty printing information from the arguments. The implementer can
314 // choose to ignore this (the default will return None) which will skip pretty
315 // printing. If you do want to pretty print, it is recommended to use the
316 // implementation of this method from RustcDefaultCalls.
317 // FIXME, this is a terrible bit of API. Parsing of pretty printing stuff
318 // should be done as part of the framework and the implementor should customise
319 // handling of it. However, that is not possible atm because pretty printing
320 // essentially goes off and takes another path through the compiler which
321 // means the session is either moved or not depending on what parse_pretty
322 // returns (we could fix this by cloning, but it's another hack). The proper
323 // solution is to handle pretty printing as if it were a compiler extension,
324 // extending CompileController to make this work (see for example the treatment
325 // of save-analysis in RustcDefaultCalls::build_controller).
326 fn parse_pretty(&mut self,
328 _matches
: &getopts
::Matches
)
329 -> Option
<(PpMode
, Option
<UserIdentifiedItem
>)> {
333 // Create a CompilController struct for controlling the behaviour of
335 fn build_controller(&mut self, &Session
) -> CompileController
<'a
>;
338 // CompilerCalls instance for a regular rustc build.
339 #[derive(Copy, Clone)]
340 pub struct RustcDefaultCalls
;
342 fn handle_explain(code
: &str,
343 descriptions
: &diagnostics
::registry
::Registry
,
344 output
: ErrorOutputType
) {
345 let normalised
= if code
.starts_with("E") {
348 format
!("E{0:0>4}", code
)
350 match descriptions
.find_description(&normalised
) {
351 Some(ref description
) => {
352 // Slice off the leading newline and print.
353 print
!("{}", &description
[1..]);
356 early_error(output
, &format
!("no extended information for {}", code
));
361 fn check_cfg(sopts
: &config
::Options
,
362 output
: ErrorOutputType
) {
363 let mut emitter
: Box
<Emitter
> = match output
{
364 config
::ErrorOutputType
::HumanReadable(color_config
) => {
365 Box
::new(errors
::emitter
::BasicEmitter
::stderr(color_config
))
367 config
::ErrorOutputType
::Json
=> Box
::new(errors
::json
::JsonEmitter
::basic()),
370 let mut saw_invalid_predicate
= false;
371 for item
in sopts
.cfg
.iter() {
373 ast
::MetaItemKind
::List(ref pred
, _
) => {
374 saw_invalid_predicate
= true;
376 &format
!("invalid predicate in --cfg command line argument: `{}`",
379 errors
::Level
::Fatal
);
385 if saw_invalid_predicate
{
386 panic
!(errors
::FatalError
);
390 impl<'a
> CompilerCalls
<'a
> for RustcDefaultCalls
{
391 fn early_callback(&mut self,
392 matches
: &getopts
::Matches
,
393 sopts
: &config
::Options
,
394 descriptions
: &diagnostics
::registry
::Registry
,
395 output
: ErrorOutputType
)
397 if let Some(ref code
) = matches
.opt_str("explain") {
398 handle_explain(code
, descriptions
, output
);
399 return Compilation
::Stop
;
402 check_cfg(sopts
, output
);
403 Compilation
::Continue
406 fn no_input(&mut self,
407 matches
: &getopts
::Matches
,
408 sopts
: &config
::Options
,
409 odir
: &Option
<PathBuf
>,
410 ofile
: &Option
<PathBuf
>,
411 descriptions
: &diagnostics
::registry
::Registry
)
412 -> Option
<(Input
, Option
<PathBuf
>)> {
413 match matches
.free
.len() {
415 if sopts
.describe_lints
{
416 let mut ls
= lint
::LintStore
::new();
417 rustc_lint
::register_builtins(&mut ls
, None
);
418 describe_lints(&ls
, false);
421 let cstore
= Rc
::new(CStore
::new(token
::get_ident_interner()));
422 let sess
= build_session(sopts
.clone(), None
, descriptions
.clone(),
424 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
425 let should_stop
= RustcDefaultCalls
::print_crate_info(&sess
, None
, odir
, ofile
);
426 if should_stop
== Compilation
::Stop
{
429 early_error(sopts
.error_format
, "no input filename given");
431 1 => panic
!("make_input should have provided valid inputs"),
432 _
=> early_error(sopts
.error_format
, "multiple input filenames provided"),
438 fn parse_pretty(&mut self,
440 matches
: &getopts
::Matches
)
441 -> Option
<(PpMode
, Option
<UserIdentifiedItem
>)> {
442 let pretty
= if sess
.opts
.debugging_opts
.unstable_options
{
443 matches
.opt_default("pretty", "normal").map(|a
| {
444 // stable pretty-print variants only
445 pretty
::parse_pretty(sess
, &a
, false)
450 if pretty
.is_none() && sess
.unstable_options() {
451 matches
.opt_str("unpretty").map(|a
| {
452 // extended with unstable pretty-print variants
453 pretty
::parse_pretty(sess
, &a
, true)
460 fn late_callback(&mut self,
461 matches
: &getopts
::Matches
,
464 odir
: &Option
<PathBuf
>,
465 ofile
: &Option
<PathBuf
>)
467 RustcDefaultCalls
::print_crate_info(sess
, Some(input
), odir
, ofile
)
468 .and_then(|| RustcDefaultCalls
::list_metadata(sess
, matches
, input
))
471 fn build_controller(&mut self, sess
: &Session
) -> CompileController
<'a
> {
472 let mut control
= CompileController
::basic();
474 if sess
.opts
.parse_only
|| sess
.opts
.debugging_opts
.show_span
.is_some() ||
475 sess
.opts
.debugging_opts
.ast_json_noexpand
{
476 control
.after_parse
.stop
= Compilation
::Stop
;
479 if sess
.opts
.no_analysis
|| sess
.opts
.debugging_opts
.ast_json
{
480 control
.after_write_deps
.stop
= Compilation
::Stop
;
483 if sess
.opts
.no_trans
{
484 control
.after_analysis
.stop
= Compilation
::Stop
;
487 if !sess
.opts
.output_types
.keys().any(|&i
| i
== OutputType
::Exe
) {
488 control
.after_llvm
.stop
= Compilation
::Stop
;
491 if sess
.opts
.debugging_opts
.save_analysis
{
492 control
.after_analysis
.callback
= box |state
| {
493 time(state
.session
.time_passes(), "save analysis", || {
494 save
::process_crate(state
.tcx
.unwrap(),
496 state
.krate
.unwrap(),
497 state
.analysis
.unwrap(),
498 state
.crate_name
.unwrap(),
502 control
.after_analysis
.run_callback_on_error
= true;
503 control
.make_glob_map
= resolve
::MakeGlobMap
::Yes
;
510 impl RustcDefaultCalls
{
511 pub fn list_metadata(sess
: &Session
, matches
: &getopts
::Matches
, input
: &Input
) -> Compilation
{
512 let r
= matches
.opt_strs("Z");
513 if r
.contains(&("ls".to_string())) {
515 &Input
::File(ref ifile
) => {
516 let path
= &(*ifile
);
517 let mut v
= Vec
::new();
518 loader
::list_file_metadata(&sess
.target
.target
, path
, &mut v
)
520 println
!("{}", String
::from_utf8(v
).unwrap());
522 &Input
::Str { .. }
=> {
523 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
526 return Compilation
::Stop
;
529 return Compilation
::Continue
;
533 fn print_crate_info(sess
: &Session
,
534 input
: Option
<&Input
>,
535 odir
: &Option
<PathBuf
>,
536 ofile
: &Option
<PathBuf
>)
538 if sess
.opts
.prints
.is_empty() {
539 return Compilation
::Continue
;
542 let attrs
= match input
{
545 let result
= parse_crate_attrs(sess
, input
);
547 Ok(attrs
) => Some(attrs
),
548 Err(mut parse_error
) => {
550 return Compilation
::Stop
;
555 for req
in &sess
.opts
.prints
{
557 PrintRequest
::TargetList
=> {
558 let mut targets
= rustc_back
::target
::TARGETS
.to_vec();
560 println
!("{}", targets
.join("\n"));
562 PrintRequest
::Sysroot
=> println
!("{}", sess
.sysroot().display()),
563 PrintRequest
::FileNames
|
564 PrintRequest
::CrateName
=> {
565 let input
= match input
{
566 Some(input
) => input
,
567 None
=> early_error(ErrorOutputType
::default(), "no input file provided"),
569 let attrs
= attrs
.as_ref().unwrap();
570 let t_outputs
= driver
::build_output_filenames(input
, odir
, ofile
, attrs
, sess
);
571 let id
= link
::find_crate_name(Some(sess
), attrs
, input
);
572 if *req
== PrintRequest
::CrateName
{
576 let crate_types
= driver
::collect_crate_types(sess
, attrs
);
577 for &style
in &crate_types
{
578 let fname
= link
::filename_for_input(sess
, style
, &id
, &t_outputs
);
585 PrintRequest
::Cfg
=> {
586 let mut cfg
= config
::build_configuration(&sess
);
587 target_features
::add_configuration(&mut cfg
, &sess
);
589 let allow_unstable_cfg
= match get_unstable_features_setting() {
590 UnstableFeatures
::Disallow
=> false,
595 if !allow_unstable_cfg
&& GatedCfg
::gate(&*cfg
).is_some() {
599 ast
::MetaItemKind
::Word(ref word
) => println
!("{}", word
),
600 ast
::MetaItemKind
::NameValue(ref name
, ref value
) => {
601 println
!("{}=\"{}\"", name
, match value
.node
{
602 ast
::LitKind
::Str(ref s
, _
) => s
,
606 // Right now there are not and should not be any
607 // MetaItemKind::List items in the configuration returned by
608 // `build_configuration`.
609 ast
::MetaItemKind
::List(..) => {
610 panic
!("MetaItemKind::List encountered in default cfg")
617 return Compilation
::Stop
;
621 /// Returns a version string such as "0.12.0-dev".
622 pub fn release_str() -> Option
<&'
static str> {
623 option_env
!("CFG_RELEASE")
626 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
627 pub fn commit_hash_str() -> Option
<&'
static str> {
628 option_env
!("CFG_VER_HASH")
631 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
632 pub fn commit_date_str() -> Option
<&'
static str> {
633 option_env
!("CFG_VER_DATE")
636 /// Prints version information
637 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
638 let verbose
= matches
.opt_present("verbose");
642 option_env
!("CFG_VERSION").unwrap_or("unknown version"));
644 fn unw(x
: Option
<&str>) -> &str {
645 x
.unwrap_or("unknown")
647 println
!("binary: {}", binary
);
648 println
!("commit-hash: {}", unw(commit_hash_str()));
649 println
!("commit-date: {}", unw(commit_date_str()));
650 println
!("host: {}", config
::host_triple());
651 println
!("release: {}", unw(release_str()));
655 fn usage(verbose
: bool
, include_unstable_options
: bool
) {
656 let groups
= if verbose
{
657 config
::rustc_optgroups()
659 config
::rustc_short_optgroups()
661 let groups
: Vec
<_
> = groups
.into_iter()
662 .filter(|x
| include_unstable_options
|| x
.is_stable())
663 .map(|x
| x
.opt_group
)
665 let message
= format
!("Usage: rustc [OPTIONS] INPUT");
666 let extra_help
= if verbose
{
669 "\n --help -v Print the full set of options rustc accepts"
671 println
!("{}\nAdditional help:
672 -C help Print codegen options
674 Print 'lint' options and default settings
675 -Z help Print internal \
676 options for debugging rustc{}\n",
677 getopts
::usage(&message
, &groups
),
681 fn describe_lints(lint_store
: &lint
::LintStore
, loaded_plugins
: bool
) {
683 Available lint options:
684 -W <foo> Warn about <foo>
688 -F <foo> Forbid <foo> \
689 (deny, and deny all overrides)
693 fn sort_lints(lints
: Vec
<(&'
static Lint
, bool
)>) -> Vec
<&'
static Lint
> {
694 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, _
)| x
).collect();
695 lints
.sort_by(|x
: &&Lint
, y
: &&Lint
| {
696 match x
.default_level
.cmp(&y
.default_level
) {
697 // The sort doesn't case-fold but it's doubtful we care.
698 Equal
=> x
.name
.cmp(y
.name
),
705 fn sort_lint_groups(lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>, bool
)>)
706 -> Vec
<(&'
static str, Vec
<lint
::LintId
>)> {
707 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
708 lints
.sort_by(|&(x
, _
): &(&'
static str, Vec
<lint
::LintId
>),
709 &(y
, _
): &(&'
static str, Vec
<lint
::LintId
>)| {
715 let (plugin
, builtin
): (Vec
<_
>, _
) = lint_store
.get_lints()
718 .partition(|&(_
, p
)| p
);
719 let plugin
= sort_lints(plugin
);
720 let builtin
= sort_lints(builtin
);
722 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) = lint_store
.get_lint_groups()
725 .partition(|&(_
, _
, p
)| p
);
726 let plugin_groups
= sort_lint_groups(plugin_groups
);
727 let builtin_groups
= sort_lint_groups(builtin_groups
);
729 let max_name_len
= plugin
.iter()
731 .map(|&s
| s
.name
.chars().count())
734 let padded
= |x
: &str| {
735 let mut s
= repeat(" ")
736 .take(max_name_len
- x
.chars().count())
737 .collect
::<String
>();
742 println
!("Lint checks provided by rustc:\n");
743 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
744 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
746 let print_lints
= |lints
: Vec
<&Lint
>| {
748 let name
= lint
.name_lower().replace("_", "-");
749 println
!(" {} {:7.7} {}",
751 lint
.default_level
.as_str(),
757 print_lints(builtin
);
761 let max_name_len
= max("warnings".len(),
763 .chain(&builtin_groups
)
764 .map(|&(s
, _
)| s
.chars().count())
768 let padded
= |x
: &str| {
769 let mut s
= repeat(" ")
770 .take(max_name_len
- x
.chars().count())
771 .collect
::<String
>();
776 println
!("Lint groups provided by rustc:\n");
777 println
!(" {} {}", padded("name"), "sub-lints");
778 println
!(" {} {}", padded("----"), "---------");
779 println
!(" {} {}", padded("warnings"), "all built-in lints");
781 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>)>| {
782 for (name
, to
) in lints
{
783 let name
= name
.to_lowercase().replace("_", "-");
784 let desc
= to
.into_iter()
785 .map(|x
| x
.as_str().replace("_", "-"))
786 .collect
::<Vec
<String
>>()
788 println
!(" {} {}", padded(&name
[..]), desc
);
793 print_lint_groups(builtin_groups
);
795 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
796 (false, 0, _
) | (false, _
, 0) => {
797 println
!("Compiler plugins can provide additional lints and lint groups. To see a \
798 listing of these, re-run `rustc -W help` with a crate filename.");
800 (false, _
, _
) => panic
!("didn't load lint plugins but got them anyway!"),
801 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
804 println
!("Lint checks provided by plugins loaded by this crate:\n");
808 println
!("Lint groups provided by plugins loaded by this crate:\n");
809 print_lint_groups(plugin_groups
);
815 fn describe_debug_flags() {
816 println
!("\nAvailable debug options:\n");
817 print_flag_list("-Z", config
::DB_OPTIONS
);
820 fn describe_codegen_flags() {
821 println
!("\nAvailable codegen options:\n");
822 print_flag_list("-C", config
::CG_OPTIONS
);
825 fn print_flag_list
<T
>(cmdline_opt
: &str,
826 flag_list
: &[(&'
static str, T
, Option
<&'
static str>, &'
static str)]) {
827 let max_len
= flag_list
.iter()
828 .map(|&(name
, _
, opt_type_desc
, _
)| {
829 let extra_len
= match opt_type_desc
{
833 name
.chars().count() + extra_len
838 for &(name
, _
, opt_type_desc
, desc
) in flag_list
{
839 let (width
, extra
) = match opt_type_desc
{
840 Some(..) => (max_len
- 4, "=val"),
841 None
=> (max_len
, ""),
843 println
!(" {} {:>width$}{} -- {}",
845 name
.replace("_", "-"),
852 /// Process command line options. Emits messages as appropriate. If compilation
853 /// should continue, returns a getopts::Matches object parsed from args,
854 /// otherwise returns None.
856 /// The compiler's handling of options is a little complication as it ties into
857 /// our stability story, and it's even *more* complicated by historical
858 /// accidents. The current intention of each compiler option is to have one of
861 /// 1. An option is stable and can be used everywhere.
862 /// 2. An option is unstable, but was historically allowed on the stable
864 /// 3. An option is unstable, and can only be used on nightly.
866 /// Like unstable library and language features, however, unstable options have
867 /// always required a form of "opt in" to indicate that you're using them. This
868 /// provides the easy ability to scan a code base to check to see if anything
869 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
871 /// All options behind `-Z` are considered unstable by default. Other top-level
872 /// options can also be considered unstable, and they were unlocked through the
873 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
874 /// instability in both cases, though.
876 /// So with all that in mind, the comments below have some more detail about the
877 /// contortions done here to get things to work out correctly.
878 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
879 // Throw away the first argument, the name of the binary
880 let args
= &args
[1..];
883 // user did not write `-v` nor `-Z unstable-options`, so do not
884 // include that extra information.
889 // Parse with *all* options defined in the compiler, we don't worry about
890 // option stability here we just want to parse as much as possible.
891 let all_groups
: Vec
<getopts
::OptGroup
> = config
::rustc_optgroups()
893 .map(|x
| x
.opt_group
)
895 let matches
= match getopts
::getopts(&args
[..], &all_groups
) {
897 Err(f
) => early_error(ErrorOutputType
::default(), &f
.to_string()),
900 // For all options we just parsed, we check a few aspects:
902 // * If the option is stable, we're all good
903 // * If the option wasn't passed, we're all good
904 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
905 // ourselves), then we require the `-Z unstable-options` flag to unlock
906 // this option that was passed.
907 // * If we're a nightly compiler, then unstable options are now unlocked, so
909 // * Otherwise, if we're a truly unstable option then we generate an error
910 // (unstable option being used on stable)
911 // * If we're a historically stable-but-should-be-unstable option then we
912 // emit a warning that we're going to turn this into an error soon.
913 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
915 if matches
.opt_present("h") || matches
.opt_present("help") {
916 // Only show unstable options in --help if we *really* accept unstable
917 // options, which catches the case where we got `-Z unstable-options` on
918 // the stable channel of Rust which was accidentally allowed
920 usage(matches
.opt_present("verbose"),
921 nightly_options
::is_unstable_enabled(&matches
));
925 // Don't handle -W help here, because we might first load plugins.
926 let r
= matches
.opt_strs("Z");
927 if r
.iter().any(|x
| *x
== "help") {
928 describe_debug_flags();
932 let cg_flags
= matches
.opt_strs("C");
933 if cg_flags
.iter().any(|x
| *x
== "help") {
934 describe_codegen_flags();
938 if cg_flags
.contains(&"passes=list".to_string()) {
940 ::llvm
::LLVMRustPrintPasses();
945 if matches
.opt_present("version") {
946 version("rustc", &matches
);
953 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
955 Input
::File(ref ifile
) => {
956 parse
::parse_crate_attrs_from_file(ifile
, Vec
::new(), &sess
.parse_sess
)
958 Input
::Str { ref name, ref input }
=> {
959 parse
::parse_crate_attrs_from_source_str(name
.clone(),
967 /// Run a procedure which will detect panics in the compiler and print nicer
968 /// error messages rather than just failing the test.
970 /// The diagnostic emitter yielded to the procedure should be used for reporting
971 /// errors of the compiler.
972 pub fn monitor
<F
: FnOnce() + Send
+ '
static>(f
: F
) {
973 const STACK_SIZE
: usize = 8 * 1024 * 1024; // 8MB
975 struct Sink(Arc
<Mutex
<Vec
<u8>>>);
976 impl Write
for Sink
{
977 fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
978 Write
::write(&mut *self.0.lock().unwrap(), data
)
980 fn flush(&mut self) -> io
::Result
<()> {
985 let data
= Arc
::new(Mutex
::new(Vec
::new()));
986 let err
= Sink(data
.clone());
988 let mut cfg
= thread
::Builder
::new().name("rustc".to_string());
990 // FIXME: Hacks on hacks. If the env is trying to override the stack size
991 // then *don't* set it explicitly.
992 if env
::var_os("RUST_MIN_STACK").is_none() {
993 cfg
= cfg
.stack_size(STACK_SIZE
);
996 let thread
= cfg
.spawn(move || {
997 io
::set_panic(box err
);
1001 if let Err(value
) = thread
.unwrap().join() {
1002 // Thread panicked without emitting a fatal diagnostic
1003 if !value
.is
::<errors
::FatalError
>() {
1004 let mut emitter
= errors
::emitter
::BasicEmitter
::stderr(errors
::ColorConfig
::Auto
);
1006 // a .span_bug or .bug call has already printed what
1007 // it wants to print.
1008 if !value
.is
::<errors
::ExplicitBug
>() {
1009 emitter
.emit(None
, "unexpected panic", None
, errors
::Level
::Bug
);
1012 let xs
= ["the compiler unexpectedly panicked. this is a bug.".to_string(),
1013 format
!("we would appreciate a bug report: {}", BUG_REPORT_URL
)];
1015 emitter
.emit(None
, ¬e
[..], None
, errors
::Level
::Note
)
1017 if match env
::var_os("RUST_BACKTRACE") {
1018 Some(val
) => &val
!= "0",
1022 "run with `RUST_BACKTRACE=1` for a backtrace",
1024 errors
::Level
::Note
);
1027 println
!("{}", str::from_utf8(&data
.lock().unwrap()).unwrap());
1034 fn exit_on_err() -> ! {
1035 // Panic so the process returns a failure code, but don't pollute the
1036 // output with some unnecessary panic messages, we've already
1037 // printed everything that we needed to.
1038 io
::set_panic(box io
::sink());
1042 pub fn diagnostics_registry() -> diagnostics
::registry
::Registry
{
1043 use syntax
::diagnostics
::registry
::Registry
;
1045 let mut all_errors
= Vec
::new();
1046 all_errors
.extend_from_slice(&rustc
::DIAGNOSTICS
);
1047 all_errors
.extend_from_slice(&rustc_typeck
::DIAGNOSTICS
);
1048 all_errors
.extend_from_slice(&rustc_borrowck
::DIAGNOSTICS
);
1049 all_errors
.extend_from_slice(&rustc_resolve
::DIAGNOSTICS
);
1050 all_errors
.extend_from_slice(&rustc_privacy
::DIAGNOSTICS
);
1051 all_errors
.extend_from_slice(&rustc_trans
::DIAGNOSTICS
);
1052 all_errors
.extend_from_slice(&rustc_const_eval
::DIAGNOSTICS
);
1054 Registry
::new(&all_errors
)
1058 let result
= run(env
::args().collect());
1059 process
::exit(result
as i32);