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 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
18 html_favicon_url
= "https://doc.rust-lang.org/favicon.ico",
19 html_root_url
= "https://doc.rust-lang.org/nightly/")]
22 #![feature(box_syntax)]
23 #![cfg_attr(unix, feature(libc))]
25 #![feature(rustc_diagnostic_macros)]
26 #![feature(set_stdio)]
30 extern crate graphviz
;
31 extern crate env_logger
;
35 extern crate rustc_allocator
;
36 extern crate rustc_back
;
37 extern crate rustc_borrowck
;
38 extern crate rustc_const_eval
;
39 extern crate rustc_data_structures
;
40 extern crate rustc_errors
as errors
;
41 extern crate rustc_passes
;
42 extern crate rustc_lint
;
43 extern crate rustc_plugin
;
44 extern crate rustc_privacy
;
45 extern crate rustc_incremental
;
46 extern crate rustc_metadata
;
47 extern crate rustc_mir
;
48 extern crate rustc_resolve
;
49 extern crate rustc_save_analysis
;
50 #[cfg(feature="llvm")]
51 extern crate rustc_trans
;
52 extern crate rustc_trans_utils
;
53 extern crate rustc_typeck
;
54 extern crate serialize
;
58 extern crate syntax_ext
;
59 extern crate syntax_pos
;
61 use driver
::CompileController
;
62 use pretty
::{PpMode, UserIdentifiedItem}
;
64 use rustc_resolve
as resolve
;
65 use rustc_save_analysis
as save
;
66 use rustc_save_analysis
::DumpHandler
;
67 use rustc
::session
::{self, config, Session, build_session, CompileResult}
;
68 use rustc
::session
::CompileIncomplete
;
69 use rustc
::session
::config
::{Input, PrintRequest, OutputType, ErrorOutputType}
;
70 use rustc
::session
::config
::nightly_options
;
71 use rustc
::session
::{early_error, early_warn}
;
72 use rustc
::lint
::Lint
;
74 use rustc
::middle
::cstore
::CrateStore
;
75 use rustc_metadata
::locator
;
76 use rustc_metadata
::cstore
::CStore
;
77 use rustc
::util
::common
::{time, ErrorReported}
;
78 use rustc_trans_utils
::trans_crate
::TransCrate
;
80 use serialize
::json
::ToJson
;
84 use std
::cmp
::Ordering
::Equal
;
85 use std
::default::Default
;
87 use std
::ffi
::OsString
;
88 use std
::io
::{self, Read, Write}
;
89 use std
::iter
::repeat
;
90 use std
::path
::PathBuf
;
91 use std
::process
::{self, Command, Stdio}
;
94 use std
::sync
::{Arc, Mutex}
;
98 use syntax
::codemap
::{CodeMap, FileLoader, RealFileLoader}
;
99 use syntax
::feature_gate
::{GatedCfg, UnstableFeatures}
;
100 use syntax
::parse
::{self, PResult}
;
101 use syntax_pos
::{DUMMY_SP, MultiSpan}
;
109 pub mod target_features
;
110 mod derive_registrar
;
112 const BUG_REPORT_URL
: &'
static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
115 pub fn abort_on_err
<T
>(result
: Result
<T
, CompileIncomplete
>, sess
: &Session
) -> T
{
117 Err(CompileIncomplete
::Errored(ErrorReported
)) => {
118 sess
.abort_if_errors();
119 panic
!("error reported but abort_if_errors didn't abort???");
121 Err(CompileIncomplete
::Stopped
) => {
122 sess
.fatal("compilation terminated");
128 pub fn run
<F
>(run_compiler
: F
) -> isize
129 where F
: FnOnce() -> (CompileResult
, Option
<Session
>) + Send
+ '
static
132 let (result
, session
) = run_compiler();
133 if let Err(CompileIncomplete
::Errored(_
)) = result
{
136 sess
.abort_if_errors();
137 panic
!("error reported but abort_if_errors didn't abort???");
141 errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
, None
);
142 let handler
= errors
::Handler
::with_emitter(true, false, Box
::new(emitter
));
143 handler
.emit(&MultiSpan
::new(),
144 "aborting due to previous error(s)",
145 errors
::Level
::Fatal
);
154 #[cfg(not(feature="llvm"))]
155 pub use rustc_trans_utils
::trans_crate
::MetadataOnlyTransCrate
as DefaultTransCrate
;
156 #[cfg(feature="llvm")]
157 pub use rustc_trans
::LlvmTransCrate
as DefaultTransCrate
;
159 #[cfg(not(feature="llvm"))]
161 use syntax_pos
::symbol
::Symbol
;
162 use rustc
::session
::Session
;
163 use rustc
::session
::config
::PrintRequest
;
164 pub use rustc_trans_utils
::trans_crate
::MetadataOnlyTransCrate
as LlvmTransCrate
;
165 pub use rustc_trans_utils
::trans_crate
::TranslatedCrate
as CrateTranslation
;
167 pub fn init(_sess
: &Session
) {}
168 pub fn enable_llvm_debug() {}
169 pub fn print_version() {}
170 pub fn print_passes() {}
171 pub fn print(_req
: PrintRequest
, _sess
: &Session
) {}
172 pub fn target_features(_sess
: &Session
) -> Vec
<Symbol
> { vec![] }
176 pub const RELOC_MODEL_ARGS
: [(&'
static str, ()); 0] = [];
177 pub const CODE_GEN_MODEL_ARGS
: [(&'
static str, ()); 0] = [];
182 // Parse args and run the compiler. This is the primary entry point for rustc.
183 // See comments on CompilerCalls below for details about the callbacks argument.
184 // The FileLoader provides a way to load files from sources other than the file system.
185 pub fn run_compiler
<'a
>(args
: &[String
],
186 callbacks
: &mut CompilerCalls
<'a
>,
187 file_loader
: Option
<Box
<FileLoader
+ '
static>>,
188 emitter_dest
: Option
<Box
<Write
+ Send
>>)
189 -> (CompileResult
, Option
<Session
>)
191 macro_rules
! do_or_return
{($expr
: expr
, $sess
: expr
) => {
193 Compilation
::Stop
=> return (Ok(()), $sess
),
194 Compilation
::Continue
=> {}
198 let matches
= match handle_options(args
) {
199 Some(matches
) => matches
,
200 None
=> return (Ok(()), None
),
203 let (sopts
, cfg
) = config
::build_session_options_and_crate_config(&matches
);
205 if sopts
.debugging_opts
.debug_llvm
{
206 rustc_trans
::enable_llvm_debug();
209 let descriptions
= diagnostics_registry();
211 do_or_return
!(callbacks
.early_callback(&matches
,
218 let (odir
, ofile
) = make_output(&matches
);
219 let (input
, input_file_path
) = match make_input(&matches
.free
) {
220 Some((input
, input_file_path
)) => callbacks
.some_input(input
, input_file_path
),
221 None
=> match callbacks
.no_input(&matches
, &sopts
, &cfg
, &odir
, &ofile
, &descriptions
) {
222 Some((input
, input_file_path
)) => (input
, input_file_path
),
223 None
=> return (Ok(()), None
),
227 let cstore
= Rc
::new(CStore
::new(DefaultTransCrate
::metadata_loader()));
229 let loader
= file_loader
.unwrap_or(box RealFileLoader
);
230 let codemap
= Rc
::new(CodeMap
::with_file_loader(loader
, sopts
.file_path_mapping()));
231 let mut sess
= session
::build_session_with_codemap(
232 sopts
, input_file_path
, descriptions
, codemap
, emitter_dest
,
234 rustc_trans
::init(&sess
);
235 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
237 let mut cfg
= config
::build_configuration(&sess
, cfg
);
238 target_features
::add_configuration(&mut cfg
, &sess
);
239 sess
.parse_sess
.config
= cfg
;
241 do_or_return
!(callbacks
.late_callback(&matches
,
246 &ofile
), Some(sess
));
248 let plugins
= sess
.opts
.debugging_opts
.extra_plugins
.clone();
249 let control
= callbacks
.build_controller(&sess
, &matches
);
250 (driver
::compile_input(&sess
,
260 // Extract output directory and file from matches.
261 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
262 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
263 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
267 // Extract input (string or file and optional path) from matches.
268 fn make_input(free_matches
: &[String
]) -> Option
<(Input
, Option
<PathBuf
>)> {
269 if free_matches
.len() == 1 {
270 let ifile
= &free_matches
[0];
272 let mut src
= String
::new();
273 io
::stdin().read_to_string(&mut src
).unwrap();
274 Some((Input
::Str { name: driver::anon_src(), input: src }
,
277 Some((Input
::File(PathBuf
::from(ifile
)),
278 Some(PathBuf
::from(ifile
))))
285 fn parse_pretty(sess
: &Session
,
286 matches
: &getopts
::Matches
)
287 -> Option
<(PpMode
, Option
<UserIdentifiedItem
>)> {
288 let pretty
= if sess
.opts
.debugging_opts
.unstable_options
{
289 matches
.opt_default("pretty", "normal").map(|a
| {
290 // stable pretty-print variants only
291 pretty
::parse_pretty(sess
, &a
, false)
296 if pretty
.is_none() && sess
.unstable_options() {
297 matches
.opt_str("unpretty").map(|a
| {
298 // extended with unstable pretty-print variants
299 pretty
::parse_pretty(sess
, &a
, true)
306 // Whether to stop or continue compilation.
307 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
308 pub enum Compilation
{
314 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
316 Compilation
::Stop
=> Compilation
::Stop
,
317 Compilation
::Continue
=> next(),
322 // A trait for customising the compilation process. Offers a number of hooks for
323 // executing custom code or customising input.
324 pub trait CompilerCalls
<'a
> {
325 // Hook for a callback early in the process of handling arguments. This will
326 // be called straight after options have been parsed but before anything
327 // else (e.g., selecting input and output).
328 fn early_callback(&mut self,
329 _
: &getopts
::Matches
,
331 _
: &ast
::CrateConfig
,
332 _
: &errors
::registry
::Registry
,
335 Compilation
::Continue
338 // Hook for a callback late in the process of handling arguments. This will
339 // be called just before actual compilation starts (and before build_controller
340 // is called), after all arguments etc. have been completely handled.
341 fn late_callback(&mut self,
342 _
: &getopts
::Matches
,
349 Compilation
::Continue
352 // Called after we extract the input from the arguments. Gives the implementer
353 // an opportunity to change the inputs or to add some custom input handling.
354 // The default behaviour is to simply pass through the inputs.
355 fn some_input(&mut self,
357 input_path
: Option
<PathBuf
>)
358 -> (Input
, Option
<PathBuf
>) {
362 // Called after we extract the input from the arguments if there is no valid
363 // input. Gives the implementer an opportunity to supply alternate input (by
364 // returning a Some value) or to add custom behaviour for this error such as
365 // emitting error messages. Returning None will cause compilation to stop
367 fn no_input(&mut self,
368 _
: &getopts
::Matches
,
370 _
: &ast
::CrateConfig
,
373 _
: &errors
::registry
::Registry
)
374 -> Option
<(Input
, Option
<PathBuf
>)> {
378 // Create a CompilController struct for controlling the behaviour of
380 fn build_controller(&mut self, _
: &Session
, _
: &getopts
::Matches
) -> CompileController
<'a
>;
383 // CompilerCalls instance for a regular rustc build.
384 #[derive(Copy, Clone)]
385 pub struct RustcDefaultCalls
;
387 // FIXME remove these and use winapi 0.3 instead
388 // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
390 fn stdout_isatty() -> bool
{
391 unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
395 fn stdout_isatty() -> bool
{
398 type HANDLE
= *mut u8;
399 type LPDWORD
= *mut u32;
400 const STD_OUTPUT_HANDLE
: DWORD
= -11i32 as DWORD
;
402 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
403 fn GetConsoleMode(hConsoleHandle
: HANDLE
, lpMode
: LPDWORD
) -> BOOL
;
406 let handle
= GetStdHandle(STD_OUTPUT_HANDLE
);
408 GetConsoleMode(handle
, &mut out
) != 0
412 fn handle_explain(code
: &str,
413 descriptions
: &errors
::registry
::Registry
,
414 output
: ErrorOutputType
) {
415 let normalised
= if code
.starts_with("E") {
418 format
!("E{0:0>4}", code
)
420 match descriptions
.find_description(&normalised
) {
421 Some(ref description
) => {
422 let mut is_in_code_block
= false;
423 let mut text
= String
::new();
425 // Slice off the leading newline and print.
426 for line
in description
[1..].lines() {
427 let indent_level
= line
.find(|c
: char| !c
.is_whitespace())
428 .unwrap_or_else(|| line
.len());
429 let dedented_line
= &line
[indent_level
..];
430 if dedented_line
.starts_with("```") {
431 is_in_code_block
= !is_in_code_block
;
432 text
.push_str(&line
[..(indent_level
+3)]);
433 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
442 show_content_with_pager(&text
);
448 early_error(output
, &format
!("no extended information for {}", code
));
453 fn show_content_with_pager(content
: &String
) {
454 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| if cfg
!(windows
) {
455 OsString
::from("more.com")
457 OsString
::from("less")
460 let mut fallback_to_println
= false;
462 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
464 if let Some(pipe
) = pager
.stdin
.as_mut() {
465 if pipe
.write_all(content
.as_bytes()).is_err() {
466 fallback_to_println
= true;
470 if pager
.wait().is_err() {
471 fallback_to_println
= true;
475 fallback_to_println
= true;
479 // If pager fails for whatever reason, we should still print the content
480 // to standard output
481 if fallback_to_println
{
482 print
!("{}", content
);
486 impl<'a
> CompilerCalls
<'a
> for RustcDefaultCalls
{
487 fn early_callback(&mut self,
488 matches
: &getopts
::Matches
,
490 _
: &ast
::CrateConfig
,
491 descriptions
: &errors
::registry
::Registry
,
492 output
: ErrorOutputType
)
494 if let Some(ref code
) = matches
.opt_str("explain") {
495 handle_explain(code
, descriptions
, output
);
496 return Compilation
::Stop
;
499 Compilation
::Continue
502 fn no_input(&mut self,
503 matches
: &getopts
::Matches
,
504 sopts
: &config
::Options
,
505 cfg
: &ast
::CrateConfig
,
506 odir
: &Option
<PathBuf
>,
507 ofile
: &Option
<PathBuf
>,
508 descriptions
: &errors
::registry
::Registry
)
509 -> Option
<(Input
, Option
<PathBuf
>)> {
510 match matches
.free
.len() {
512 if sopts
.describe_lints
{
513 let mut ls
= lint
::LintStore
::new();
514 rustc_lint
::register_builtins(&mut ls
, None
);
515 describe_lints(&ls
, false);
518 let mut sess
= build_session(sopts
.clone(),
520 descriptions
.clone());
521 rustc_trans
::init(&sess
);
522 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
523 let mut cfg
= config
::build_configuration(&sess
, cfg
.clone());
524 target_features
::add_configuration(&mut cfg
, &sess
);
525 sess
.parse_sess
.config
= cfg
;
527 RustcDefaultCalls
::print_crate_info(&sess
, None
, odir
, ofile
);
529 if should_stop
== Compilation
::Stop
{
532 early_error(sopts
.error_format
, "no input filename given");
534 1 => panic
!("make_input should have provided valid inputs"),
535 _
=> early_error(sopts
.error_format
, "multiple input filenames provided"),
539 fn late_callback(&mut self,
540 matches
: &getopts
::Matches
,
544 odir
: &Option
<PathBuf
>,
545 ofile
: &Option
<PathBuf
>)
547 RustcDefaultCalls
::print_crate_info(sess
, Some(input
), odir
, ofile
)
548 .and_then(|| RustcDefaultCalls
::list_metadata(sess
, cstore
, matches
, input
))
551 fn build_controller(&mut self,
553 matches
: &getopts
::Matches
)
554 -> CompileController
<'a
> {
555 let mut control
= CompileController
::basic();
557 control
.keep_ast
= sess
.opts
.debugging_opts
.keep_ast
;
558 control
.continue_parse_after_error
= sess
.opts
.debugging_opts
.continue_parse_after_error
;
560 if let Some((ppm
, opt_uii
)) = parse_pretty(sess
, matches
) {
561 if ppm
.needs_ast_map(&opt_uii
) {
562 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
564 control
.after_parse
.callback
= box move |state
| {
565 state
.krate
= Some(pretty
::fold_crate(state
.krate
.take().unwrap(), ppm
));
567 control
.after_hir_lowering
.callback
= box move |state
| {
568 pretty
::print_after_hir_lowering(state
.session
,
569 state
.cstore
.unwrap(),
570 state
.hir_map
.unwrap(),
571 state
.analysis
.unwrap(),
572 state
.resolutions
.unwrap(),
574 &state
.expanded_crate
.take().unwrap(),
575 state
.crate_name
.unwrap(),
577 state
.arena
.unwrap(),
578 state
.arenas
.unwrap(),
579 state
.output_filenames
.unwrap(),
584 control
.after_parse
.stop
= Compilation
::Stop
;
586 control
.after_parse
.callback
= box move |state
| {
587 let krate
= pretty
::fold_crate(state
.krate
.take().unwrap(), ppm
);
588 pretty
::print_after_parsing(state
.session
,
599 if sess
.opts
.debugging_opts
.parse_only
||
600 sess
.opts
.debugging_opts
.show_span
.is_some() ||
601 sess
.opts
.debugging_opts
.ast_json_noexpand
{
602 control
.after_parse
.stop
= Compilation
::Stop
;
605 if sess
.opts
.debugging_opts
.no_analysis
||
606 sess
.opts
.debugging_opts
.ast_json
{
607 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
610 if !sess
.opts
.output_types
.keys().any(|&i
| i
== OutputType
::Exe
||
611 i
== OutputType
::Metadata
) {
612 control
.after_llvm
.stop
= Compilation
::Stop
;
615 if save_analysis(sess
) {
616 enable_save_analysis(&mut control
);
619 if sess
.print_fuel_crate
.is_some() {
620 let old_callback
= control
.compilation_done
.callback
;
621 control
.compilation_done
.callback
= box move |state
| {
623 let sess
= state
.session
;
624 println
!("Fuel used by {}: {}",
625 sess
.print_fuel_crate
.as_ref().unwrap(),
626 sess
.print_fuel
.get());
633 pub fn enable_save_analysis(control
: &mut CompileController
) {
634 control
.keep_ast
= true;
635 control
.after_analysis
.callback
= box |state
| {
636 time(state
.session
.time_passes(), "save analysis", || {
637 save
::process_crate(state
.tcx
.unwrap(),
638 state
.expanded_crate
.unwrap(),
639 state
.analysis
.unwrap(),
640 state
.crate_name
.unwrap(),
642 DumpHandler
::new(state
.out_dir
,
643 state
.crate_name
.unwrap()))
646 control
.after_analysis
.run_callback_on_error
= true;
647 control
.make_glob_map
= resolve
::MakeGlobMap
::Yes
;
650 fn save_analysis(sess
: &Session
) -> bool
{
651 sess
.opts
.debugging_opts
.save_analysis
654 impl RustcDefaultCalls
{
655 pub fn list_metadata(sess
: &Session
,
657 matches
: &getopts
::Matches
,
660 let r
= matches
.opt_strs("Z");
661 if r
.contains(&("ls".to_string())) {
663 &Input
::File(ref ifile
) => {
664 let path
= &(*ifile
);
665 let mut v
= Vec
::new();
666 locator
::list_file_metadata(&sess
.target
.target
,
668 cstore
.metadata_loader(),
671 println
!("{}", String
::from_utf8(v
).unwrap());
673 &Input
::Str { .. }
=> {
674 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
677 return Compilation
::Stop
;
680 return Compilation
::Continue
;
684 fn print_crate_info(sess
: &Session
,
685 input
: Option
<&Input
>,
686 odir
: &Option
<PathBuf
>,
687 ofile
: &Option
<PathBuf
>)
689 // PrintRequest::NativeStaticLibs is special - printed during linking
690 // (empty iterator returns true)
691 if sess
.opts
.prints
.iter().all(|&p
| p
==PrintRequest
::NativeStaticLibs
) {
692 return Compilation
::Continue
;
695 let attrs
= match input
{
698 let result
= parse_crate_attrs(sess
, input
);
700 Ok(attrs
) => Some(attrs
),
701 Err(mut parse_error
) => {
703 return Compilation
::Stop
;
708 for req
in &sess
.opts
.prints
{
710 PrintRequest
::TargetList
=> {
711 let mut targets
= rustc_back
::target
::get_targets().collect
::<Vec
<String
>>();
713 println
!("{}", targets
.join("\n"));
715 PrintRequest
::Sysroot
=> println
!("{}", sess
.sysroot().display()),
716 PrintRequest
::TargetSpec
=> println
!("{}", sess
.target
.target
.to_json().pretty()),
717 PrintRequest
::FileNames
|
718 PrintRequest
::CrateName
=> {
719 let input
= match input
{
720 Some(input
) => input
,
721 None
=> early_error(ErrorOutputType
::default(), "no input file provided"),
723 let attrs
= attrs
.as_ref().unwrap();
724 let t_outputs
= driver
::build_output_filenames(input
, odir
, ofile
, attrs
, sess
);
725 let id
= rustc_trans_utils
::link
::find_crate_name(Some(sess
), attrs
, input
);
726 if *req
== PrintRequest
::CrateName
{
730 let crate_types
= driver
::collect_crate_types(sess
, attrs
);
731 for &style
in &crate_types
{
732 let fname
= rustc_trans_utils
::link
::filename_for_input(
744 PrintRequest
::Cfg
=> {
745 let allow_unstable_cfg
= UnstableFeatures
::from_environment()
748 let mut cfgs
= Vec
::new();
749 for &(name
, ref value
) in sess
.parse_sess
.config
.iter() {
750 let gated_cfg
= GatedCfg
::gate(&ast
::MetaItem
{
752 node
: ast
::MetaItemKind
::Word
,
756 // Note that crt-static is a specially recognized cfg
757 // directive that's printed out here as part of
758 // rust-lang/rust#37406, but in general the
759 // `target_feature` cfg is gated under
760 // rust-lang/rust#29717. For now this is just
761 // specifically allowing the crt-static cfg and that's
762 // it, this is intended to get into Cargo and then go
763 // through to build scripts.
764 let value
= value
.as_ref().map(|s
| s
.as_str());
765 let value
= value
.as_ref().map(|s
| s
.as_ref());
766 if name
!= "target_feature" || value
!= Some("crt-static") {
767 if !allow_unstable_cfg
&& gated_cfg
.is_some() {
772 cfgs
.push(if let Some(value
) = value
{
773 format
!("{}=\"{}\"", name
, value
)
784 PrintRequest
::RelocationModels
=> {
785 println
!("Available relocation models:");
786 for &(name
, _
) in rustc_trans
::back
::write
::RELOC_MODEL_ARGS
.iter() {
787 println
!(" {}", name
);
791 PrintRequest
::CodeModels
=> {
792 println
!("Available code models:");
793 for &(name
, _
) in rustc_trans
::back
::write
::CODE_GEN_MODEL_ARGS
.iter(){
794 println
!(" {}", name
);
798 PrintRequest
::TargetCPUs
| PrintRequest
::TargetFeatures
=> {
799 rustc_trans
::print(*req
, sess
);
801 PrintRequest
::NativeStaticLibs
=> {
802 println
!("Native static libs can be printed only during linking");
806 return Compilation
::Stop
;
810 /// Returns a version string such as "0.12.0-dev".
811 fn release_str() -> Option
<&'
static str> {
812 option_env
!("CFG_RELEASE")
815 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
816 fn commit_hash_str() -> Option
<&'
static str> {
817 option_env
!("CFG_VER_HASH")
820 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
821 fn commit_date_str() -> Option
<&'
static str> {
822 option_env
!("CFG_VER_DATE")
825 /// Prints version information
826 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
827 let verbose
= matches
.opt_present("verbose");
831 option_env
!("CFG_VERSION").unwrap_or("unknown version"));
833 fn unw(x
: Option
<&str>) -> &str {
834 x
.unwrap_or("unknown")
836 println
!("binary: {}", binary
);
837 println
!("commit-hash: {}", unw(commit_hash_str()));
838 println
!("commit-date: {}", unw(commit_date_str()));
839 println
!("host: {}", config
::host_triple());
840 println
!("release: {}", unw(release_str()));
841 rustc_trans
::print_version();
845 fn usage(verbose
: bool
, include_unstable_options
: bool
) {
846 let groups
= if verbose
{
847 config
::rustc_optgroups()
849 config
::rustc_short_optgroups()
851 let mut options
= getopts
::Options
::new();
852 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
853 (option
.apply
)(&mut options
);
855 let message
= format
!("Usage: rustc [OPTIONS] INPUT");
856 let nightly_help
= if nightly_options
::is_nightly_build() {
857 "\n -Z help Print internal options for debugging rustc"
861 let verbose_help
= if verbose
{
864 "\n --help -v Print the full set of options rustc accepts"
866 println
!("{}\nAdditional help:
867 -C help Print codegen options
869 Print 'lint' options and default settings{}{}\n",
870 options
.usage(&message
),
875 fn describe_lints(lint_store
: &lint
::LintStore
, loaded_plugins
: bool
) {
877 Available lint options:
878 -W <foo> Warn about <foo>
882 -F <foo> Forbid <foo> \
883 (deny <foo> and all attempts to override)
887 fn sort_lints(lints
: Vec
<(&'
static Lint
, bool
)>) -> Vec
<&'
static Lint
> {
888 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, _
)| x
).collect();
889 lints
.sort_by(|x
: &&Lint
, y
: &&Lint
| {
890 match x
.default_level
.cmp(&y
.default_level
) {
891 // The sort doesn't case-fold but it's doubtful we care.
892 Equal
=> x
.name
.cmp(y
.name
),
899 fn sort_lint_groups(lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>, bool
)>)
900 -> Vec
<(&'
static str, Vec
<lint
::LintId
>)> {
901 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
902 lints
.sort_by(|&(x
, _
): &(&'
static str, Vec
<lint
::LintId
>),
903 &(y
, _
): &(&'
static str, Vec
<lint
::LintId
>)| {
909 let (plugin
, builtin
): (Vec
<_
>, _
) = lint_store
.get_lints()
912 .partition(|&(_
, p
)| p
);
913 let plugin
= sort_lints(plugin
);
914 let builtin
= sort_lints(builtin
);
916 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) = lint_store
.get_lint_groups()
919 .partition(|&(.., p
)| p
);
920 let plugin_groups
= sort_lint_groups(plugin_groups
);
921 let builtin_groups
= sort_lint_groups(builtin_groups
);
923 let max_name_len
= plugin
.iter()
925 .map(|&s
| s
.name
.chars().count())
928 let padded
= |x
: &str| {
929 let mut s
= repeat(" ")
930 .take(max_name_len
- x
.chars().count())
931 .collect
::<String
>();
936 println
!("Lint checks provided by rustc:\n");
937 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
938 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
940 let print_lints
= |lints
: Vec
<&Lint
>| {
942 let name
= lint
.name_lower().replace("_", "-");
943 println
!(" {} {:7.7} {}",
945 lint
.default_level
.as_str(),
951 print_lints(builtin
);
955 let max_name_len
= max("warnings".len(),
957 .chain(&builtin_groups
)
958 .map(|&(s
, _
)| s
.chars().count())
962 let padded
= |x
: &str| {
963 let mut s
= repeat(" ")
964 .take(max_name_len
- x
.chars().count())
965 .collect
::<String
>();
970 println
!("Lint groups provided by rustc:\n");
971 println
!(" {} {}", padded("name"), "sub-lints");
972 println
!(" {} {}", padded("----"), "---------");
973 println
!(" {} {}", padded("warnings"), "all built-in lints");
975 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>)>| {
976 for (name
, to
) in lints
{
977 let name
= name
.to_lowercase().replace("_", "-");
978 let desc
= to
.into_iter()
979 .map(|x
| x
.to_string().replace("_", "-"))
980 .collect
::<Vec
<String
>>()
982 println
!(" {} {}", padded(&name
), desc
);
987 print_lint_groups(builtin_groups
);
989 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
990 (false, 0, _
) | (false, _
, 0) => {
991 println
!("Compiler plugins can provide additional lints and lint groups. To see a \
992 listing of these, re-run `rustc -W help` with a crate filename.");
994 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
995 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
998 println
!("Lint checks provided by plugins loaded by this crate:\n");
1002 println
!("Lint groups provided by plugins loaded by this crate:\n");
1003 print_lint_groups(plugin_groups
);
1009 fn describe_debug_flags() {
1010 println
!("\nAvailable debug options:\n");
1011 print_flag_list("-Z", config
::DB_OPTIONS
);
1014 fn describe_codegen_flags() {
1015 println
!("\nAvailable codegen options:\n");
1016 print_flag_list("-C", config
::CG_OPTIONS
);
1019 fn print_flag_list
<T
>(cmdline_opt
: &str,
1020 flag_list
: &[(&'
static str, T
, Option
<&'
static str>, &'
static str)]) {
1021 let max_len
= flag_list
.iter()
1022 .map(|&(name
, _
, opt_type_desc
, _
)| {
1023 let extra_len
= match opt_type_desc
{
1027 name
.chars().count() + extra_len
1032 for &(name
, _
, opt_type_desc
, desc
) in flag_list
{
1033 let (width
, extra
) = match opt_type_desc
{
1034 Some(..) => (max_len
- 4, "=val"),
1035 None
=> (max_len
, ""),
1037 println
!(" {} {:>width$}{} -- {}",
1039 name
.replace("_", "-"),
1046 /// Process command line options. Emits messages as appropriate. If compilation
1047 /// should continue, returns a getopts::Matches object parsed from args,
1048 /// otherwise returns None.
1050 /// The compiler's handling of options is a little complicated as it ties into
1051 /// our stability story, and it's even *more* complicated by historical
1052 /// accidents. The current intention of each compiler option is to have one of
1055 /// 1. An option is stable and can be used everywhere.
1056 /// 2. An option is unstable, but was historically allowed on the stable
1058 /// 3. An option is unstable, and can only be used on nightly.
1060 /// Like unstable library and language features, however, unstable options have
1061 /// always required a form of "opt in" to indicate that you're using them. This
1062 /// provides the easy ability to scan a code base to check to see if anything
1063 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
1065 /// All options behind `-Z` are considered unstable by default. Other top-level
1066 /// options can also be considered unstable, and they were unlocked through the
1067 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
1068 /// instability in both cases, though.
1070 /// So with all that in mind, the comments below have some more detail about the
1071 /// contortions done here to get things to work out correctly.
1072 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
1073 // Throw away the first argument, the name of the binary
1074 let args
= &args
[1..];
1076 if args
.is_empty() {
1077 // user did not write `-v` nor `-Z unstable-options`, so do not
1078 // include that extra information.
1079 usage(false, false);
1083 // Parse with *all* options defined in the compiler, we don't worry about
1084 // option stability here we just want to parse as much as possible.
1085 let mut options
= getopts
::Options
::new();
1086 for option
in config
::rustc_optgroups() {
1087 (option
.apply
)(&mut options
);
1089 let matches
= match options
.parse(args
) {
1091 Err(f
) => early_error(ErrorOutputType
::default(), &f
.to_string()),
1094 // For all options we just parsed, we check a few aspects:
1096 // * If the option is stable, we're all good
1097 // * If the option wasn't passed, we're all good
1098 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1099 // ourselves), then we require the `-Z unstable-options` flag to unlock
1100 // this option that was passed.
1101 // * If we're a nightly compiler, then unstable options are now unlocked, so
1102 // we're good to go.
1103 // * Otherwise, if we're a truly unstable option then we generate an error
1104 // (unstable option being used on stable)
1105 // * If we're a historically stable-but-should-be-unstable option then we
1106 // emit a warning that we're going to turn this into an error soon.
1107 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1109 if matches
.opt_present("h") || matches
.opt_present("help") {
1110 // Only show unstable options in --help if we *really* accept unstable
1111 // options, which catches the case where we got `-Z unstable-options` on
1112 // the stable channel of Rust which was accidentally allowed
1114 usage(matches
.opt_present("verbose"),
1115 nightly_options
::is_unstable_enabled(&matches
));
1119 // Don't handle -W help here, because we might first load plugins.
1120 let r
= matches
.opt_strs("Z");
1121 if r
.iter().any(|x
| *x
== "help") {
1122 describe_debug_flags();
1126 let cg_flags
= matches
.opt_strs("C");
1127 if cg_flags
.iter().any(|x
| *x
== "help") {
1128 describe_codegen_flags();
1132 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1133 early_warn(ErrorOutputType
::default(),
1134 "the --no-stack-check flag is deprecated and does nothing");
1137 if cg_flags
.contains(&"passes=list".to_string()) {
1138 rustc_trans
::print_passes();
1142 if matches
.opt_present("version") {
1143 version("rustc", &matches
);
1150 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1152 Input
::File(ref ifile
) => {
1153 parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
)
1155 Input
::Str { ref name, ref input }
=> {
1156 parse
::parse_crate_attrs_from_source_str(name
.clone(), input
.clone(), &sess
.parse_sess
)
1161 /// Runs `f` in a suitable thread for running `rustc`; returns a
1162 /// `Result` with either the return value of `f` or -- if a panic
1163 /// occurs -- the panic value.
1164 pub fn in_rustc_thread
<F
, R
>(f
: F
) -> Result
<R
, Box
<Any
+ Send
>>
1165 where F
: FnOnce() -> R
+ Send
+ '
static,
1168 // Temporarily have stack size set to 16MB to deal with nom-using crates failing
1169 const STACK_SIZE
: usize = 16 * 1024 * 1024; // 16MB
1171 let mut cfg
= thread
::Builder
::new().name("rustc".to_string());
1173 // FIXME: Hacks on hacks. If the env is trying to override the stack size
1174 // then *don't* set it explicitly.
1175 if env
::var_os("RUST_MIN_STACK").is_none() {
1176 cfg
= cfg
.stack_size(STACK_SIZE
);
1179 let thread
= cfg
.spawn(f
);
1180 thread
.unwrap().join()
1183 /// Run a procedure which will detect panics in the compiler and print nicer
1184 /// error messages rather than just failing the test.
1186 /// The diagnostic emitter yielded to the procedure should be used for reporting
1187 /// errors of the compiler.
1188 pub fn monitor
<F
: FnOnce() + Send
+ '
static>(f
: F
) {
1189 struct Sink(Arc
<Mutex
<Vec
<u8>>>);
1190 impl Write
for Sink
{
1191 fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
1192 Write
::write(&mut *self.0.lock().unwrap(), data
)
1194 fn flush(&mut self) -> io
::Result
<()> {
1199 let data
= Arc
::new(Mutex
::new(Vec
::new()));
1200 let err
= Sink(data
.clone());
1202 let result
= in_rustc_thread(move || {
1203 io
::set_panic(Some(box err
));
1207 if let Err(value
) = result
{
1208 // Thread panicked without emitting a fatal diagnostic
1209 if !value
.is
::<errors
::FatalError
>() {
1211 Box
::new(errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
, None
));
1212 let handler
= errors
::Handler
::with_emitter(true, false, emitter
);
1214 // a .span_bug or .bug call has already printed what
1215 // it wants to print.
1216 if !value
.is
::<errors
::ExplicitBug
>() {
1217 handler
.emit(&MultiSpan
::new(),
1219 errors
::Level
::Bug
);
1222 let xs
= ["the compiler unexpectedly panicked. this is a bug.".to_string(),
1223 format
!("we would appreciate a bug report: {}", BUG_REPORT_URL
),
1224 format
!("rustc {} running on {}",
1225 option_env
!("CFG_VERSION").unwrap_or("unknown_version"),
1226 config
::host_triple())];
1228 handler
.emit(&MultiSpan
::new(),
1230 errors
::Level
::Note
);
1232 if match env
::var_os("RUST_BACKTRACE") {
1233 Some(val
) => &val
!= "0",
1236 handler
.emit(&MultiSpan
::new(),
1237 "run with `RUST_BACKTRACE=1` for a backtrace",
1238 errors
::Level
::Note
);
1241 writeln
!(io
::stderr(), "{}", str::from_utf8(&data
.lock().unwrap()).unwrap()).unwrap();
1248 fn exit_on_err() -> ! {
1249 // Panic so the process returns a failure code, but don't pollute the
1250 // output with some unnecessary panic messages, we've already
1251 // printed everything that we needed to.
1252 io
::set_panic(Some(box io
::sink()));
1256 pub fn diagnostics_registry() -> errors
::registry
::Registry
{
1257 use errors
::registry
::Registry
;
1259 let mut all_errors
= Vec
::new();
1260 all_errors
.extend_from_slice(&rustc
::DIAGNOSTICS
);
1261 all_errors
.extend_from_slice(&rustc_typeck
::DIAGNOSTICS
);
1262 all_errors
.extend_from_slice(&rustc_borrowck
::DIAGNOSTICS
);
1263 all_errors
.extend_from_slice(&rustc_resolve
::DIAGNOSTICS
);
1264 all_errors
.extend_from_slice(&rustc_privacy
::DIAGNOSTICS
);
1265 #[cfg(feature="llvm")]
1266 all_errors
.extend_from_slice(&rustc_trans
::DIAGNOSTICS
);
1267 all_errors
.extend_from_slice(&rustc_const_eval
::DIAGNOSTICS
);
1268 all_errors
.extend_from_slice(&rustc_metadata
::DIAGNOSTICS
);
1269 all_errors
.extend_from_slice(&rustc_passes
::DIAGNOSTICS
);
1270 all_errors
.extend_from_slice(&rustc_plugin
::DIAGNOSTICS
);
1271 all_errors
.extend_from_slice(&rustc_mir
::DIAGNOSTICS
);
1272 all_errors
.extend_from_slice(&syntax
::DIAGNOSTICS
);
1274 Registry
::new(&all_errors
)
1277 pub fn get_args() -> Vec
<String
> {
1278 env
::args_os().enumerate()
1279 .map(|(i
, arg
)| arg
.into_string().unwrap_or_else(|arg
| {
1280 early_error(ErrorOutputType
::default(),
1281 &format
!("Argument {} is not valid Unicode: {:?}", i
, arg
))
1287 env_logger
::init().unwrap();
1288 let result
= run(|| run_compiler(&get_args(),
1289 &mut RustcDefaultCalls
,
1292 process
::exit(result
as i32);