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 extern crate rustc_trans_utils
;
51 extern crate rustc_typeck
;
52 extern crate serialize
;
56 extern crate syntax_ext
;
57 extern crate syntax_pos
;
59 use driver
::CompileController
;
60 use pretty
::{PpMode, UserIdentifiedItem}
;
62 use rustc_resolve
as resolve
;
63 use rustc_save_analysis
as save
;
64 use rustc_save_analysis
::DumpHandler
;
65 use rustc
::session
::{self, config, Session, build_session, CompileResult}
;
66 use rustc
::session
::CompileIncomplete
;
67 use rustc
::session
::config
::{Input, PrintRequest, ErrorOutputType}
;
68 use rustc
::session
::config
::nightly_options
;
69 use rustc
::session
::filesearch
;
70 use rustc
::session
::{early_error, early_warn}
;
71 use rustc
::lint
::Lint
;
73 use rustc
::middle
::cstore
::CrateStore
;
74 use rustc_metadata
::locator
;
75 use rustc_metadata
::cstore
::CStore
;
76 use rustc_metadata
::dynamic_lib
::DynamicLibrary
;
77 use rustc
::util
::common
::{time, ErrorReported}
;
78 use rustc_trans_utils
::trans_crate
::TransCrate
;
80 use serialize
::json
::ToJson
;
83 use std
::cmp
::Ordering
::Equal
;
85 use std
::default::Default
;
86 use std
::env
::consts
::{DLL_PREFIX, DLL_SUFFIX}
;
88 use std
::ffi
::OsString
;
89 use std
::io
::{self, Read, Write}
;
90 use std
::iter
::repeat
;
93 use std
::path
::{PathBuf, Path}
;
94 use std
::process
::{self, Command, Stdio}
;
97 use std
::sync
::atomic
::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}
;
98 use std
::sync
::{Once, ONCE_INIT}
;
102 use syntax
::codemap
::{CodeMap, FileLoader, RealFileLoader}
;
103 use syntax
::feature_gate
::{GatedCfg, UnstableFeatures}
;
104 use syntax
::parse
::{self, PResult}
;
105 use syntax_pos
::{DUMMY_SP, MultiSpan, FileName}
;
113 mod derive_registrar
;
115 pub mod target_features
{
117 use syntax
::symbol
::Symbol
;
118 use rustc
::session
::Session
;
119 use rustc_trans_utils
::trans_crate
::TransCrate
;
121 /// Add `target_feature = "..."` cfgs for a variety of platform
122 /// specific features (SSE, NEON etc.).
124 /// This is performed by checking whether a whitelisted set of
125 /// features is available on the target machine, by querying LLVM.
126 pub fn add_configuration(cfg
: &mut ast
::CrateConfig
, sess
: &Session
, trans
: &TransCrate
) {
127 let tf
= Symbol
::intern("target_feature");
129 for feat
in trans
.target_features(sess
) {
130 cfg
.insert((tf
, Some(feat
)));
133 if sess
.crt_static_feature() {
134 cfg
.insert((tf
, Some(Symbol
::intern("crt-static"))));
139 const BUG_REPORT_URL
: &'
static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
142 pub fn abort_on_err
<T
>(result
: Result
<T
, CompileIncomplete
>, sess
: &Session
) -> T
{
144 Err(CompileIncomplete
::Errored(ErrorReported
)) => {
145 sess
.abort_if_errors();
146 panic
!("error reported but abort_if_errors didn't abort???");
148 Err(CompileIncomplete
::Stopped
) => {
149 sess
.fatal("compilation terminated");
155 pub fn run
<F
>(run_compiler
: F
) -> isize
156 where F
: FnOnce() -> (CompileResult
, Option
<Session
>) + Send
+ '
static
159 let (result
, session
) = run_compiler();
160 if let Err(CompileIncomplete
::Errored(_
)) = result
{
163 sess
.abort_if_errors();
164 panic
!("error reported but abort_if_errors didn't abort???");
168 errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
,
172 let handler
= errors
::Handler
::with_emitter(true, false, Box
::new(emitter
));
173 handler
.emit(&MultiSpan
::new(),
174 "aborting due to previous error(s)",
175 errors
::Level
::Fatal
);
176 panic
::resume_unwind(Box
::new(errors
::FatalErrorMarker
));
184 fn load_backend_from_dylib(path
: &Path
) -> fn() -> Box
<TransCrate
> {
185 // Note that we're specifically using `open_global_now` here rather than
186 // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
187 // where NOW means "bind everything right now" because we don't want
188 // surprises later on and RTLD_GLOBAL allows the symbols to be made
189 // available for future dynamic libraries opened. This is currently used by
190 // loading LLVM and then making its symbols available for other dynamic
192 let lib
= match DynamicLibrary
::open_global_now(path
) {
195 let err
= format
!("couldn't load codegen backend {:?}: {:?}",
198 early_error(ErrorOutputType
::default(), &err
);
202 match lib
.symbol("__rustc_codegen_backend") {
205 mem
::transmute
::<*mut u8, _
>(f
)
208 let err
= format
!("couldn't load codegen backend as it \
209 doesn't export the `__rustc_codegen_backend` \
211 early_error(ErrorOutputType
::default(), &err
);
217 pub fn get_trans(sess
: &Session
) -> Box
<TransCrate
> {
218 static INIT
: Once
= ONCE_INIT
;
219 static mut LOAD
: fn() -> Box
<TransCrate
> = || unreachable
!();
222 let trans_name
= sess
.opts
.debugging_opts
.codegen_backend
.as_ref()
223 .unwrap_or(&sess
.target
.target
.options
.codegen_backend
);
224 let backend
= match &trans_name
[..] {
226 rustc_trans_utils
::trans_crate
::MetadataOnlyTransCrate
::new
228 filename
if filename
.contains(".") => {
229 load_backend_from_dylib(filename
.as_ref())
231 trans_name
=> get_trans_sysroot(trans_name
),
238 let backend
= unsafe { LOAD() }
;
243 fn get_trans_sysroot(backend_name
: &str) -> fn() -> Box
<TransCrate
> {
244 // For now we only allow this function to be called once as it'll dlopen a
245 // few things, which seems to work best if we only do that once. In
246 // general this assertion never trips due to the once guard in `get_trans`,
247 // but there's a few manual calls to this function in this file we protect
249 static LOADED
: AtomicBool
= ATOMIC_BOOL_INIT
;
250 assert
!(!LOADED
.fetch_or(true, Ordering
::SeqCst
),
251 "cannot load the default trans backend twice");
253 // When we're compiling this library with `--test` it'll run as a binary but
254 // not actually exercise much functionality. As a result most of the logic
255 // here is defunkt (it assumes we're a dynamic library in a sysroot) so
256 // let's just return a dummy creation function which won't be used in
259 return rustc_trans_utils
::trans_crate
::MetadataOnlyTransCrate
::new
262 let target
= session
::config
::host_triple();
263 let mut sysroot_candidates
= vec
![filesearch
::get_or_default_sysroot()];
264 let path
= current_dll_path()
265 .and_then(|s
| s
.canonicalize().ok());
266 if let Some(dll
) = path
{
267 // use `parent` twice to chop off the file name and then also the
268 // directory containing the dll which should be either `lib` or `bin`.
269 if let Some(path
) = dll
.parent().and_then(|p
| p
.parent()) {
270 // The original `path` pointed at the `rustc_driver` crate's dll.
271 // Now that dll should only be in one of two locations. The first is
272 // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
273 // other is the target's libdir, for example
274 // `$sysroot/lib/rustlib/$target/lib/*.dll`.
276 // We don't know which, so let's assume that if our `path` above
277 // ends in `$target` we *could* be in the target libdir, and always
278 // assume that we may be in the main libdir.
279 sysroot_candidates
.push(path
.to_owned());
281 if path
.ends_with(target
) {
282 sysroot_candidates
.extend(path
.parent() // chop off `$target`
283 .and_then(|p
| p
.parent()) // chop off `rustlib`
284 .and_then(|p
| p
.parent()) // chop off `lib`
285 .map(|s
| s
.to_owned()));
290 let sysroot
= sysroot_candidates
.iter()
292 let libdir
= filesearch
::relative_target_lib_path(&sysroot
, &target
);
293 sysroot
.join(libdir
).with_file_name("codegen-backends")
296 info
!("codegen backend candidate: {}", f
.display());
300 let sysroot
= match sysroot
{
303 let candidates
= sysroot_candidates
.iter()
304 .map(|p
| p
.display().to_string())
307 let err
= format
!("failed to find a `codegen-backends` folder \
308 in the sysroot candidates:\n* {}", candidates
);
309 early_error(ErrorOutputType
::default(), &err
);
312 info
!("probing {} for a codegen backend", sysroot
.display());
314 let d
= match sysroot
.read_dir() {
317 let err
= format
!("failed to load default codegen backend, couldn't \
318 read `{}`: {}", sysroot
.display(), e
);
319 early_error(ErrorOutputType
::default(), &err
);
323 let mut file
: Option
<PathBuf
> = None
;
325 let expected_name
= format
!("rustc_trans-{}", backend_name
);
326 for entry
in d
.filter_map(|e
| e
.ok()) {
327 let path
= entry
.path();
328 let filename
= match path
.file_name().and_then(|s
| s
.to_str()) {
332 if !(filename
.starts_with(DLL_PREFIX
) && filename
.ends_with(DLL_SUFFIX
)) {
335 let name
= &filename
[DLL_PREFIX
.len() .. filename
.len() - DLL_SUFFIX
.len()];
336 if name
!= expected_name
{
339 if let Some(ref prev
) = file
{
340 let err
= format
!("duplicate codegen backends found\n\
343 ", prev
.display(), path
.display());
344 early_error(ErrorOutputType
::default(), &err
);
346 file
= Some(path
.clone());
350 Some(ref s
) => return load_backend_from_dylib(s
),
352 let err
= format
!("failed to load default codegen backend for `{}`, \
353 no appropriate codegen dylib found in `{}`",
354 backend_name
, sysroot
.display());
355 early_error(ErrorOutputType
::default(), &err
);
360 fn current_dll_path() -> Option
<PathBuf
> {
361 use std
::ffi
::{OsStr, CStr}
;
362 use std
::os
::unix
::prelude
::*;
365 let addr
= current_dll_path
as usize as *mut _
;
366 let mut info
= mem
::zeroed();
367 if libc
::dladdr(addr
, &mut info
) == 0 {
368 info
!("dladdr failed");
371 if info
.dli_fname
.is_null() {
372 info
!("dladdr returned null pointer");
375 let bytes
= CStr
::from_ptr(info
.dli_fname
).to_bytes();
376 let os
= OsStr
::from_bytes(bytes
);
377 Some(PathBuf
::from(os
))
382 fn current_dll_path() -> Option
<PathBuf
> {
383 use std
::ffi
::OsString
;
384 use std
::os
::windows
::prelude
::*;
387 fn GetModuleHandleExW(dwFlags
: u32,
389 phModule
: *mut usize) -> i32;
390 fn GetModuleFileNameW(hModule
: usize,
391 lpFilename
: *mut u16,
395 const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
: u32 = 0x00000004;
399 let r
= GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
400 current_dll_path
as usize,
403 info
!("GetModuleHandleExW failed: {}", io
::Error
::last_os_error());
406 let mut space
= Vec
::with_capacity(1024);
407 let r
= GetModuleFileNameW(module
,
409 space
.capacity() as u32);
411 info
!("GetModuleFileNameW failed: {}", io
::Error
::last_os_error());
415 if r
>= space
.capacity() {
416 info
!("our buffer was too small? {}",
417 io
::Error
::last_os_error());
421 let os
= OsString
::from_wide(&space
);
422 Some(PathBuf
::from(os
))
427 // Parse args and run the compiler. This is the primary entry point for rustc.
428 // See comments on CompilerCalls below for details about the callbacks argument.
429 // The FileLoader provides a way to load files from sources other than the file system.
430 pub fn run_compiler
<'a
>(args
: &[String
],
431 callbacks
: &mut CompilerCalls
<'a
>,
432 file_loader
: Option
<Box
<FileLoader
+ '
static>>,
433 emitter_dest
: Option
<Box
<Write
+ Send
>>)
434 -> (CompileResult
, Option
<Session
>)
436 macro_rules
! do_or_return
{($expr
: expr
, $sess
: expr
) => {
438 Compilation
::Stop
=> return (Ok(()), $sess
),
439 Compilation
::Continue
=> {}
443 let matches
= match handle_options(args
) {
444 Some(matches
) => matches
,
445 None
=> return (Ok(()), None
),
448 let (sopts
, cfg
) = config
::build_session_options_and_crate_config(&matches
);
450 let descriptions
= diagnostics_registry();
452 do_or_return
!(callbacks
.early_callback(&matches
,
459 let (odir
, ofile
) = make_output(&matches
);
460 let (input
, input_file_path
, input_err
) = match make_input(&matches
.free
) {
461 Some((input
, input_file_path
, input_err
)) => {
462 let (input
, input_file_path
) = callbacks
.some_input(input
, input_file_path
);
463 (input
, input_file_path
, input_err
)
465 None
=> match callbacks
.no_input(&matches
, &sopts
, &cfg
, &odir
, &ofile
, &descriptions
) {
466 Some((input
, input_file_path
)) => (input
, input_file_path
, None
),
467 None
=> return (Ok(()), None
),
471 let loader
= file_loader
.unwrap_or(box RealFileLoader
);
472 let codemap
= Rc
::new(CodeMap
::with_file_loader(loader
, sopts
.file_path_mapping()));
473 let mut sess
= session
::build_session_with_codemap(
474 sopts
, input_file_path
.clone(), descriptions
, codemap
, emitter_dest
,
477 if let Some(err
) = input_err
{
478 // Immediately stop compilation if there was an issue reading
479 // the input (for example if the input stream is not UTF-8).
480 sess
.err(&format
!("{}", err
));
481 return (Err(CompileIncomplete
::Stopped
), Some(sess
));
484 let trans
= get_trans(&sess
);
486 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
488 let mut cfg
= config
::build_configuration(&sess
, cfg
);
489 target_features
::add_configuration(&mut cfg
, &sess
, &*trans
);
490 sess
.parse_sess
.config
= cfg
;
492 let plugins
= sess
.opts
.debugging_opts
.extra_plugins
.clone();
494 let cstore
= CStore
::new(trans
.metadata_loader());
496 do_or_return
!(callbacks
.late_callback(&*trans
,
502 &ofile
), Some(sess
));
504 let control
= callbacks
.build_controller(&sess
, &matches
);
506 (driver
::compile_input(trans
,
518 // Extract output directory and file from matches.
519 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
520 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
521 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
525 // Extract input (string or file and optional path) from matches.
526 fn make_input(free_matches
: &[String
]) -> Option
<(Input
, Option
<PathBuf
>, Option
<io
::Error
>)> {
527 if free_matches
.len() == 1 {
528 let ifile
= &free_matches
[0];
530 let mut src
= String
::new();
531 let err
= if io
::stdin().read_to_string(&mut src
).is_err() {
532 Some(io
::Error
::new(io
::ErrorKind
::InvalidData
,
533 "couldn't read from stdin, as it did not contain valid UTF-8"))
537 Some((Input
::Str { name: FileName::Anon, input: src }
,
540 Some((Input
::File(PathBuf
::from(ifile
)),
541 Some(PathBuf
::from(ifile
)), None
))
548 fn parse_pretty(sess
: &Session
,
549 matches
: &getopts
::Matches
)
550 -> Option
<(PpMode
, Option
<UserIdentifiedItem
>)> {
551 let pretty
= if sess
.opts
.debugging_opts
.unstable_options
{
552 matches
.opt_default("pretty", "normal").map(|a
| {
553 // stable pretty-print variants only
554 pretty
::parse_pretty(sess
, &a
, false)
560 if pretty
.is_none() {
561 sess
.opts
.debugging_opts
.unpretty
.as_ref().map(|a
| {
562 // extended with unstable pretty-print variants
563 pretty
::parse_pretty(sess
, &a
, true)
570 // Whether to stop or continue compilation.
571 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
572 pub enum Compilation
{
578 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
580 Compilation
::Stop
=> Compilation
::Stop
,
581 Compilation
::Continue
=> next(),
586 // A trait for customising the compilation process. Offers a number of hooks for
587 // executing custom code or customising input.
588 pub trait CompilerCalls
<'a
> {
589 // Hook for a callback early in the process of handling arguments. This will
590 // be called straight after options have been parsed but before anything
591 // else (e.g., selecting input and output).
592 fn early_callback(&mut self,
593 _
: &getopts
::Matches
,
595 _
: &ast
::CrateConfig
,
596 _
: &errors
::registry
::Registry
,
599 Compilation
::Continue
602 // Hook for a callback late in the process of handling arguments. This will
603 // be called just before actual compilation starts (and before build_controller
604 // is called), after all arguments etc. have been completely handled.
605 fn late_callback(&mut self,
607 _
: &getopts
::Matches
,
614 Compilation
::Continue
617 // Called after we extract the input from the arguments. Gives the implementer
618 // an opportunity to change the inputs or to add some custom input handling.
619 // The default behaviour is to simply pass through the inputs.
620 fn some_input(&mut self,
622 input_path
: Option
<PathBuf
>)
623 -> (Input
, Option
<PathBuf
>) {
627 // Called after we extract the input from the arguments if there is no valid
628 // input. Gives the implementer an opportunity to supply alternate input (by
629 // returning a Some value) or to add custom behaviour for this error such as
630 // emitting error messages. Returning None will cause compilation to stop
632 fn no_input(&mut self,
633 _
: &getopts
::Matches
,
635 _
: &ast
::CrateConfig
,
638 _
: &errors
::registry
::Registry
)
639 -> Option
<(Input
, Option
<PathBuf
>)> {
643 // Create a CompilController struct for controlling the behaviour of
645 fn build_controller(&mut self, _
: &Session
, _
: &getopts
::Matches
) -> CompileController
<'a
>;
648 // CompilerCalls instance for a regular rustc build.
649 #[derive(Copy, Clone)]
650 pub struct RustcDefaultCalls
;
652 // FIXME remove these and use winapi 0.3 instead
653 // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
655 fn stdout_isatty() -> bool
{
656 unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
660 fn stdout_isatty() -> bool
{
663 type HANDLE
= *mut u8;
664 type LPDWORD
= *mut u32;
665 const STD_OUTPUT_HANDLE
: DWORD
= -11i32 as DWORD
;
667 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
668 fn GetConsoleMode(hConsoleHandle
: HANDLE
, lpMode
: LPDWORD
) -> BOOL
;
671 let handle
= GetStdHandle(STD_OUTPUT_HANDLE
);
673 GetConsoleMode(handle
, &mut out
) != 0
677 fn handle_explain(code
: &str,
678 descriptions
: &errors
::registry
::Registry
,
679 output
: ErrorOutputType
) {
680 let normalised
= if code
.starts_with("E") {
683 format
!("E{0:0>4}", code
)
685 match descriptions
.find_description(&normalised
) {
686 Some(ref description
) => {
687 let mut is_in_code_block
= false;
688 let mut text
= String
::new();
690 // Slice off the leading newline and print.
691 for line
in description
[1..].lines() {
692 let indent_level
= line
.find(|c
: char| !c
.is_whitespace())
693 .unwrap_or_else(|| line
.len());
694 let dedented_line
= &line
[indent_level
..];
695 if dedented_line
.starts_with("```") {
696 is_in_code_block
= !is_in_code_block
;
697 text
.push_str(&line
[..(indent_level
+3)]);
698 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
707 show_content_with_pager(&text
);
713 early_error(output
, &format
!("no extended information for {}", code
));
718 fn show_content_with_pager(content
: &String
) {
719 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| if cfg
!(windows
) {
720 OsString
::from("more.com")
722 OsString
::from("less")
725 let mut fallback_to_println
= false;
727 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
729 if let Some(pipe
) = pager
.stdin
.as_mut() {
730 if pipe
.write_all(content
.as_bytes()).is_err() {
731 fallback_to_println
= true;
735 if pager
.wait().is_err() {
736 fallback_to_println
= true;
740 fallback_to_println
= true;
744 // If pager fails for whatever reason, we should still print the content
745 // to standard output
746 if fallback_to_println
{
747 print
!("{}", content
);
751 impl<'a
> CompilerCalls
<'a
> for RustcDefaultCalls
{
752 fn early_callback(&mut self,
753 matches
: &getopts
::Matches
,
755 _
: &ast
::CrateConfig
,
756 descriptions
: &errors
::registry
::Registry
,
757 output
: ErrorOutputType
)
759 if let Some(ref code
) = matches
.opt_str("explain") {
760 handle_explain(code
, descriptions
, output
);
761 return Compilation
::Stop
;
764 Compilation
::Continue
767 fn no_input(&mut self,
768 matches
: &getopts
::Matches
,
769 sopts
: &config
::Options
,
770 cfg
: &ast
::CrateConfig
,
771 odir
: &Option
<PathBuf
>,
772 ofile
: &Option
<PathBuf
>,
773 descriptions
: &errors
::registry
::Registry
)
774 -> Option
<(Input
, Option
<PathBuf
>)> {
775 match matches
.free
.len() {
777 if sopts
.describe_lints
{
778 let mut ls
= lint
::LintStore
::new();
779 rustc_lint
::register_builtins(&mut ls
, None
);
780 describe_lints(&ls
, false);
783 let mut sess
= build_session(sopts
.clone(),
785 descriptions
.clone());
786 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
787 let mut cfg
= config
::build_configuration(&sess
, cfg
.clone());
788 let trans
= get_trans(&sess
);
789 target_features
::add_configuration(&mut cfg
, &sess
, &*trans
);
790 sess
.parse_sess
.config
= cfg
;
791 let should_stop
= RustcDefaultCalls
::print_crate_info(
799 if should_stop
== Compilation
::Stop
{
802 early_error(sopts
.error_format
, "no input filename given");
804 1 => panic
!("make_input should have provided valid inputs"),
805 _
=> early_error(sopts
.error_format
, "multiple input filenames provided"),
809 fn late_callback(&mut self,
811 matches
: &getopts
::Matches
,
815 odir
: &Option
<PathBuf
>,
816 ofile
: &Option
<PathBuf
>)
818 RustcDefaultCalls
::print_crate_info(trans
, sess
, Some(input
), odir
, ofile
)
819 .and_then(|| RustcDefaultCalls
::list_metadata(sess
, cstore
, matches
, input
))
822 fn build_controller(&mut self,
824 matches
: &getopts
::Matches
)
825 -> CompileController
<'a
> {
826 let mut control
= CompileController
::basic();
828 control
.keep_ast
= sess
.opts
.debugging_opts
.keep_ast
;
829 control
.continue_parse_after_error
= sess
.opts
.debugging_opts
.continue_parse_after_error
;
831 if let Some((ppm
, opt_uii
)) = parse_pretty(sess
, matches
) {
832 if ppm
.needs_ast_map(&opt_uii
) {
833 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
835 control
.after_parse
.callback
= box move |state
| {
836 state
.krate
= Some(pretty
::fold_crate(state
.session
,
837 state
.krate
.take().unwrap(),
840 control
.after_hir_lowering
.callback
= box move |state
| {
841 pretty
::print_after_hir_lowering(state
.session
,
842 state
.cstore
.unwrap(),
843 state
.hir_map
.unwrap(),
844 state
.analysis
.unwrap(),
845 state
.resolutions
.unwrap(),
847 &state
.expanded_crate
.take().unwrap(),
848 state
.crate_name
.unwrap(),
850 state
.arenas
.unwrap(),
851 state
.output_filenames
.unwrap(),
856 control
.after_parse
.stop
= Compilation
::Stop
;
858 control
.after_parse
.callback
= box move |state
| {
859 let krate
= pretty
::fold_crate(state
.session
, state
.krate
.take().unwrap(), ppm
);
860 pretty
::print_after_parsing(state
.session
,
871 if sess
.opts
.debugging_opts
.parse_only
||
872 sess
.opts
.debugging_opts
.show_span
.is_some() ||
873 sess
.opts
.debugging_opts
.ast_json_noexpand
{
874 control
.after_parse
.stop
= Compilation
::Stop
;
877 if sess
.opts
.debugging_opts
.no_analysis
||
878 sess
.opts
.debugging_opts
.ast_json
{
879 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
882 if sess
.opts
.debugging_opts
.save_analysis
{
883 enable_save_analysis(&mut control
);
886 if sess
.print_fuel_crate
.is_some() {
887 let old_callback
= control
.compilation_done
.callback
;
888 control
.compilation_done
.callback
= box move |state
| {
890 let sess
= state
.session
;
891 println
!("Fuel used by {}: {}",
892 sess
.print_fuel_crate
.as_ref().unwrap(),
893 sess
.print_fuel
.get());
900 pub fn enable_save_analysis(control
: &mut CompileController
) {
901 control
.keep_ast
= true;
902 control
.after_analysis
.callback
= box |state
| {
903 time(state
.session
.time_passes(), "save analysis", || {
904 save
::process_crate(state
.tcx
.unwrap(),
905 state
.expanded_crate
.unwrap(),
906 state
.analysis
.unwrap(),
907 state
.crate_name
.unwrap(),
909 DumpHandler
::new(state
.out_dir
,
910 state
.crate_name
.unwrap()))
913 control
.after_analysis
.run_callback_on_error
= true;
914 control
.make_glob_map
= resolve
::MakeGlobMap
::Yes
;
917 impl RustcDefaultCalls
{
918 pub fn list_metadata(sess
: &Session
,
920 matches
: &getopts
::Matches
,
923 let r
= matches
.opt_strs("Z");
924 if r
.contains(&("ls".to_string())) {
926 &Input
::File(ref ifile
) => {
927 let path
= &(*ifile
);
928 let mut v
= Vec
::new();
929 locator
::list_file_metadata(&sess
.target
.target
,
931 cstore
.metadata_loader(),
934 println
!("{}", String
::from_utf8(v
).unwrap());
936 &Input
::Str { .. }
=> {
937 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
940 return Compilation
::Stop
;
943 return Compilation
::Continue
;
947 fn print_crate_info(trans
: &TransCrate
,
949 input
: Option
<&Input
>,
950 odir
: &Option
<PathBuf
>,
951 ofile
: &Option
<PathBuf
>)
953 use rustc
::session
::config
::PrintRequest
::*;
954 // PrintRequest::NativeStaticLibs is special - printed during linking
955 // (empty iterator returns true)
956 if sess
.opts
.prints
.iter().all(|&p
| p
==PrintRequest
::NativeStaticLibs
) {
957 return Compilation
::Continue
;
960 let attrs
= match input
{
963 let result
= parse_crate_attrs(sess
, input
);
965 Ok(attrs
) => Some(attrs
),
966 Err(mut parse_error
) => {
968 return Compilation
::Stop
;
973 for req
in &sess
.opts
.prints
{
976 let mut targets
= rustc_back
::target
::get_targets().collect
::<Vec
<String
>>();
978 println
!("{}", targets
.join("\n"));
980 Sysroot
=> println
!("{}", sess
.sysroot().display()),
981 TargetSpec
=> println
!("{}", sess
.target
.target
.to_json().pretty()),
982 FileNames
| CrateName
=> {
983 let input
= match input
{
984 Some(input
) => input
,
985 None
=> early_error(ErrorOutputType
::default(), "no input file provided"),
987 let attrs
= attrs
.as_ref().unwrap();
988 let t_outputs
= driver
::build_output_filenames(input
, odir
, ofile
, attrs
, sess
);
989 let id
= rustc_trans_utils
::link
::find_crate_name(Some(sess
), attrs
, input
);
990 if *req
== PrintRequest
::CrateName
{
994 let crate_types
= driver
::collect_crate_types(sess
, attrs
);
995 for &style
in &crate_types
{
996 let fname
= rustc_trans_utils
::link
::filename_for_input(
1005 .to_string_lossy());
1009 let allow_unstable_cfg
= UnstableFeatures
::from_environment()
1010 .is_nightly_build();
1012 let mut cfgs
= Vec
::new();
1013 for &(name
, ref value
) in sess
.parse_sess
.config
.iter() {
1014 let gated_cfg
= GatedCfg
::gate(&ast
::MetaItem
{
1016 node
: ast
::MetaItemKind
::Word
,
1020 // Note that crt-static is a specially recognized cfg
1021 // directive that's printed out here as part of
1022 // rust-lang/rust#37406, but in general the
1023 // `target_feature` cfg is gated under
1024 // rust-lang/rust#29717. For now this is just
1025 // specifically allowing the crt-static cfg and that's
1026 // it, this is intended to get into Cargo and then go
1027 // through to build scripts.
1028 let value
= value
.as_ref().map(|s
| s
.as_str());
1029 let value
= value
.as_ref().map(|s
| s
.as_ref());
1030 if name
!= "target_feature" || value
!= Some("crt-static") {
1031 if !allow_unstable_cfg
&& gated_cfg
.is_some() {
1036 cfgs
.push(if let Some(value
) = value
{
1037 format
!("{}=\"{}\"", name
, value
)
1045 println
!("{}", cfg
);
1048 RelocationModels
| CodeModels
| TlsModels
| TargetCPUs
| TargetFeatures
=> {
1049 trans
.print(*req
, sess
);
1051 // Any output here interferes with Cargo's parsing of other printed output
1052 PrintRequest
::NativeStaticLibs
=> {}
1055 return Compilation
::Stop
;
1059 /// Returns a version string such as "0.12.0-dev".
1060 fn release_str() -> Option
<&'
static str> {
1061 option_env
!("CFG_RELEASE")
1064 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
1065 fn commit_hash_str() -> Option
<&'
static str> {
1066 option_env
!("CFG_VER_HASH")
1069 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
1070 fn commit_date_str() -> Option
<&'
static str> {
1071 option_env
!("CFG_VER_DATE")
1074 /// Prints version information
1075 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
1076 let verbose
= matches
.opt_present("verbose");
1080 option_env
!("CFG_VERSION").unwrap_or("unknown version"));
1082 fn unw(x
: Option
<&str>) -> &str {
1083 x
.unwrap_or("unknown")
1085 println
!("binary: {}", binary
);
1086 println
!("commit-hash: {}", unw(commit_hash_str()));
1087 println
!("commit-date: {}", unw(commit_date_str()));
1088 println
!("host: {}", config
::host_triple());
1089 println
!("release: {}", unw(release_str()));
1090 get_trans_sysroot("llvm")().print_version();
1094 fn usage(verbose
: bool
, include_unstable_options
: bool
) {
1095 let groups
= if verbose
{
1096 config
::rustc_optgroups()
1098 config
::rustc_short_optgroups()
1100 let mut options
= getopts
::Options
::new();
1101 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
1102 (option
.apply
)(&mut options
);
1104 let message
= format
!("Usage: rustc [OPTIONS] INPUT");
1105 let nightly_help
= if nightly_options
::is_nightly_build() {
1106 "\n -Z help Print internal options for debugging rustc"
1110 let verbose_help
= if verbose
{
1113 "\n --help -v Print the full set of options rustc accepts"
1115 println
!("{}\nAdditional help:
1116 -C help Print codegen options
1118 Print 'lint' options and default settings{}{}\n",
1119 options
.usage(&message
),
1124 fn describe_lints(lint_store
: &lint
::LintStore
, loaded_plugins
: bool
) {
1126 Available lint options:
1127 -W <foo> Warn about <foo>
1131 -F <foo> Forbid <foo> \
1132 (deny <foo> and all attempts to override)
1136 fn sort_lints(lints
: Vec
<(&'
static Lint
, bool
)>) -> Vec
<&'
static Lint
> {
1137 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, _
)| x
).collect();
1138 lints
.sort_by(|x
: &&Lint
, y
: &&Lint
| {
1139 match x
.default_level
.cmp(&y
.default_level
) {
1140 // The sort doesn't case-fold but it's doubtful we care.
1141 Equal
=> x
.name
.cmp(y
.name
),
1148 fn sort_lint_groups(lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>, bool
)>)
1149 -> Vec
<(&'
static str, Vec
<lint
::LintId
>)> {
1150 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
1151 lints
.sort_by(|&(x
, _
): &(&'
static str, Vec
<lint
::LintId
>),
1152 &(y
, _
): &(&'
static str, Vec
<lint
::LintId
>)| {
1158 let (plugin
, builtin
): (Vec
<_
>, _
) = lint_store
.get_lints()
1161 .partition(|&(_
, p
)| p
);
1162 let plugin
= sort_lints(plugin
);
1163 let builtin
= sort_lints(builtin
);
1165 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) = lint_store
.get_lint_groups()
1168 .partition(|&(.., p
)| p
);
1169 let plugin_groups
= sort_lint_groups(plugin_groups
);
1170 let builtin_groups
= sort_lint_groups(builtin_groups
);
1172 let max_name_len
= plugin
.iter()
1174 .map(|&s
| s
.name
.chars().count())
1177 let padded
= |x
: &str| {
1178 let mut s
= repeat(" ")
1179 .take(max_name_len
- x
.chars().count())
1180 .collect
::<String
>();
1185 println
!("Lint checks provided by rustc:\n");
1186 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
1187 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
1189 let print_lints
= |lints
: Vec
<&Lint
>| {
1191 let name
= lint
.name_lower().replace("_", "-");
1192 println
!(" {} {:7.7} {}",
1194 lint
.default_level
.as_str(),
1200 print_lints(builtin
);
1204 let max_name_len
= max("warnings".len(),
1205 plugin_groups
.iter()
1206 .chain(&builtin_groups
)
1207 .map(|&(s
, _
)| s
.chars().count())
1211 let padded
= |x
: &str| {
1212 let mut s
= repeat(" ")
1213 .take(max_name_len
- x
.chars().count())
1214 .collect
::<String
>();
1219 println
!("Lint groups provided by rustc:\n");
1220 println
!(" {} {}", padded("name"), "sub-lints");
1221 println
!(" {} {}", padded("----"), "---------");
1222 println
!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
1224 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>)>| {
1225 for (name
, to
) in lints
{
1226 let name
= name
.to_lowercase().replace("_", "-");
1227 let desc
= to
.into_iter()
1228 .map(|x
| x
.to_string().replace("_", "-"))
1229 .collect
::<Vec
<String
>>()
1231 println
!(" {} {}", padded(&name
), desc
);
1236 print_lint_groups(builtin_groups
);
1238 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
1239 (false, 0, _
) | (false, _
, 0) => {
1240 println
!("Compiler plugins can provide additional lints and lint groups. To see a \
1241 listing of these, re-run `rustc -W help` with a crate filename.");
1243 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
1244 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
1247 println
!("Lint checks provided by plugins loaded by this crate:\n");
1248 print_lints(plugin
);
1251 println
!("Lint groups provided by plugins loaded by this crate:\n");
1252 print_lint_groups(plugin_groups
);
1258 fn describe_debug_flags() {
1259 println
!("\nAvailable debug options:\n");
1260 print_flag_list("-Z", config
::DB_OPTIONS
);
1263 fn describe_codegen_flags() {
1264 println
!("\nAvailable codegen options:\n");
1265 print_flag_list("-C", config
::CG_OPTIONS
);
1268 fn print_flag_list
<T
>(cmdline_opt
: &str,
1269 flag_list
: &[(&'
static str, T
, Option
<&'
static str>, &'
static str)]) {
1270 let max_len
= flag_list
.iter()
1271 .map(|&(name
, _
, opt_type_desc
, _
)| {
1272 let extra_len
= match opt_type_desc
{
1276 name
.chars().count() + extra_len
1281 for &(name
, _
, opt_type_desc
, desc
) in flag_list
{
1282 let (width
, extra
) = match opt_type_desc
{
1283 Some(..) => (max_len
- 4, "=val"),
1284 None
=> (max_len
, ""),
1286 println
!(" {} {:>width$}{} -- {}",
1288 name
.replace("_", "-"),
1295 /// Process command line options. Emits messages as appropriate. If compilation
1296 /// should continue, returns a getopts::Matches object parsed from args,
1297 /// otherwise returns None.
1299 /// The compiler's handling of options is a little complicated as it ties into
1300 /// our stability story, and it's even *more* complicated by historical
1301 /// accidents. The current intention of each compiler option is to have one of
1304 /// 1. An option is stable and can be used everywhere.
1305 /// 2. An option is unstable, but was historically allowed on the stable
1307 /// 3. An option is unstable, and can only be used on nightly.
1309 /// Like unstable library and language features, however, unstable options have
1310 /// always required a form of "opt in" to indicate that you're using them. This
1311 /// provides the easy ability to scan a code base to check to see if anything
1312 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
1314 /// All options behind `-Z` are considered unstable by default. Other top-level
1315 /// options can also be considered unstable, and they were unlocked through the
1316 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
1317 /// instability in both cases, though.
1319 /// So with all that in mind, the comments below have some more detail about the
1320 /// contortions done here to get things to work out correctly.
1321 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
1322 // Throw away the first argument, the name of the binary
1323 let args
= &args
[1..];
1325 if args
.is_empty() {
1326 // user did not write `-v` nor `-Z unstable-options`, so do not
1327 // include that extra information.
1328 usage(false, false);
1332 // Parse with *all* options defined in the compiler, we don't worry about
1333 // option stability here we just want to parse as much as possible.
1334 let mut options
= getopts
::Options
::new();
1335 for option
in config
::rustc_optgroups() {
1336 (option
.apply
)(&mut options
);
1338 let matches
= match options
.parse(args
) {
1340 Err(f
) => early_error(ErrorOutputType
::default(), &f
.to_string()),
1343 // For all options we just parsed, we check a few aspects:
1345 // * If the option is stable, we're all good
1346 // * If the option wasn't passed, we're all good
1347 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1348 // ourselves), then we require the `-Z unstable-options` flag to unlock
1349 // this option that was passed.
1350 // * If we're a nightly compiler, then unstable options are now unlocked, so
1351 // we're good to go.
1352 // * Otherwise, if we're a truly unstable option then we generate an error
1353 // (unstable option being used on stable)
1354 // * If we're a historically stable-but-should-be-unstable option then we
1355 // emit a warning that we're going to turn this into an error soon.
1356 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1358 if matches
.opt_present("h") || matches
.opt_present("help") {
1359 // Only show unstable options in --help if we *really* accept unstable
1360 // options, which catches the case where we got `-Z unstable-options` on
1361 // the stable channel of Rust which was accidentally allowed
1363 usage(matches
.opt_present("verbose"),
1364 nightly_options
::is_unstable_enabled(&matches
));
1368 // Don't handle -W help here, because we might first load plugins.
1369 let r
= matches
.opt_strs("Z");
1370 if r
.iter().any(|x
| *x
== "help") {
1371 describe_debug_flags();
1375 let cg_flags
= matches
.opt_strs("C");
1376 if cg_flags
.iter().any(|x
| *x
== "help") {
1377 describe_codegen_flags();
1381 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1382 early_warn(ErrorOutputType
::default(),
1383 "the --no-stack-check flag is deprecated and does nothing");
1386 if cg_flags
.contains(&"passes=list".to_string()) {
1387 get_trans_sysroot("llvm")().print_passes();
1391 if matches
.opt_present("version") {
1392 version("rustc", &matches
);
1399 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1401 Input
::File(ref ifile
) => {
1402 parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
)
1404 Input
::Str { ref name, ref input }
=> {
1405 parse
::parse_crate_attrs_from_source_str(name
.clone(),
1412 /// Runs `f` in a suitable thread for running `rustc`; returns a
1413 /// `Result` with either the return value of `f` or -- if a panic
1414 /// occurs -- the panic value.
1415 pub fn in_rustc_thread
<F
, R
>(f
: F
) -> Result
<R
, Box
<Any
+ Send
>>
1416 where F
: FnOnce() -> R
+ Send
+ '
static,
1419 // Temporarily have stack size set to 16MB to deal with nom-using crates failing
1420 const STACK_SIZE
: usize = 16 * 1024 * 1024; // 16MB
1422 let mut cfg
= thread
::Builder
::new().name("rustc".to_string());
1424 // FIXME: Hacks on hacks. If the env is trying to override the stack size
1425 // then *don't* set it explicitly.
1426 if env
::var_os("RUST_MIN_STACK").is_none() {
1427 cfg
= cfg
.stack_size(STACK_SIZE
);
1430 let thread
= cfg
.spawn(f
);
1431 thread
.unwrap().join()
1434 /// Run a procedure which will detect panics in the compiler and print nicer
1435 /// error messages rather than just failing the test.
1437 /// The diagnostic emitter yielded to the procedure should be used for reporting
1438 /// errors of the compiler.
1439 pub fn monitor
<F
: FnOnce() + Send
+ '
static>(f
: F
) {
1440 let result
= in_rustc_thread(move || {
1444 if let Err(value
) = result
{
1445 // Thread panicked without emitting a fatal diagnostic
1446 if !value
.is
::<errors
::FatalErrorMarker
>() {
1451 Box
::new(errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
,
1455 let handler
= errors
::Handler
::with_emitter(true, false, emitter
);
1457 // a .span_bug or .bug call has already printed what
1458 // it wants to print.
1459 if !value
.is
::<errors
::ExplicitBug
>() {
1460 handler
.emit(&MultiSpan
::new(),
1462 errors
::Level
::Bug
);
1465 let xs
= ["the compiler unexpectedly panicked. this is a bug.".to_string(),
1466 format
!("we would appreciate a bug report: {}", BUG_REPORT_URL
),
1467 format
!("rustc {} running on {}",
1468 option_env
!("CFG_VERSION").unwrap_or("unknown_version"),
1469 config
::host_triple())];
1471 handler
.emit(&MultiSpan
::new(),
1473 errors
::Level
::Note
);
1477 panic
::resume_unwind(Box
::new(errors
::FatalErrorMarker
));
1482 pub fn diagnostics_registry() -> errors
::registry
::Registry
{
1483 use errors
::registry
::Registry
;
1489 pub fn diagnostics_registry() -> errors
::registry
::Registry
{
1490 use errors
::registry
::Registry
;
1492 let mut all_errors
= Vec
::new();
1493 all_errors
.extend_from_slice(&rustc
::DIAGNOSTICS
);
1494 all_errors
.extend_from_slice(&rustc_typeck
::DIAGNOSTICS
);
1495 all_errors
.extend_from_slice(&rustc_resolve
::DIAGNOSTICS
);
1496 all_errors
.extend_from_slice(&rustc_privacy
::DIAGNOSTICS
);
1497 // FIXME: need to figure out a way to get these back in here
1498 // all_errors.extend_from_slice(get_trans(sess).diagnostics());
1499 all_errors
.extend_from_slice(&rustc_trans_utils
::DIAGNOSTICS
);
1500 all_errors
.extend_from_slice(&rustc_const_eval
::DIAGNOSTICS
);
1501 all_errors
.extend_from_slice(&rustc_metadata
::DIAGNOSTICS
);
1502 all_errors
.extend_from_slice(&rustc_passes
::DIAGNOSTICS
);
1503 all_errors
.extend_from_slice(&rustc_plugin
::DIAGNOSTICS
);
1504 all_errors
.extend_from_slice(&rustc_mir
::DIAGNOSTICS
);
1505 all_errors
.extend_from_slice(&syntax
::DIAGNOSTICS
);
1507 Registry
::new(&all_errors
)
1511 env_logger
::init().unwrap();
1512 let result
= run(|| {
1513 let args
= env
::args_os().enumerate()
1514 .map(|(i
, arg
)| arg
.into_string().unwrap_or_else(|arg
| {
1515 early_error(ErrorOutputType
::default(),
1516 &format
!("Argument {} is not valid Unicode: {:?}", i
, arg
))
1518 .collect
::<Vec
<_
>>();
1520 &mut RustcDefaultCalls
,
1524 process
::exit(result
as i32);