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/")]
21 #![feature(box_syntax)]
22 #![cfg_attr(unix, feature(libc))]
24 #![feature(rustc_diagnostic_macros)]
25 #![feature(slice_sort_by_cached_key)]
26 #![feature(set_stdio)]
27 #![feature(rustc_stack_internals)]
30 #![recursion_limit="256"]
34 extern crate graphviz
;
35 extern crate env_logger
;
38 extern crate rustc_rayon
as rayon
;
40 extern crate rustc_allocator
;
41 extern crate rustc_target
;
42 extern crate rustc_borrowck
;
43 extern crate rustc_data_structures
;
44 extern crate rustc_errors
as errors
;
45 extern crate rustc_passes
;
46 extern crate rustc_lint
;
47 extern crate rustc_plugin
;
48 extern crate rustc_privacy
;
49 extern crate rustc_incremental
;
50 extern crate rustc_metadata
;
51 extern crate rustc_mir
;
52 extern crate rustc_resolve
;
53 extern crate rustc_save_analysis
;
54 extern crate rustc_traits
;
55 extern crate rustc_codegen_utils
;
56 extern crate rustc_typeck
;
57 extern crate scoped_tls
;
58 extern crate serialize
;
62 extern crate syntax_ext
;
63 extern crate syntax_pos
;
65 use driver
::CompileController
;
66 use pretty
::{PpMode, UserIdentifiedItem}
;
68 use rustc_resolve
as resolve
;
69 use rustc_save_analysis
as save
;
70 use rustc_save_analysis
::DumpHandler
;
71 use rustc_data_structures
::sync
::{self, Lrc}
;
72 use rustc_data_structures
::OnDrop
;
73 use rustc
::session
::{self, config, Session, build_session, CompileResult}
;
74 use rustc
::session
::CompileIncomplete
;
75 use rustc
::session
::config
::{Input, PrintRequest, ErrorOutputType}
;
76 use rustc
::session
::config
::nightly_options
;
77 use rustc
::session
::filesearch
;
78 use rustc
::session
::{early_error, early_warn}
;
79 use rustc
::lint
::Lint
;
81 use rustc
::middle
::cstore
::CrateStore
;
82 use rustc_metadata
::locator
;
83 use rustc_metadata
::cstore
::CStore
;
84 use rustc_metadata
::dynamic_lib
::DynamicLibrary
;
85 use rustc
::util
::common
::{time, ErrorReported}
;
86 use rustc_codegen_utils
::codegen_backend
::CodegenBackend
;
88 use serialize
::json
::ToJson
;
92 use std
::default::Default
;
93 use std
::env
::consts
::{DLL_PREFIX, DLL_SUFFIX}
;
95 use std
::ffi
::OsString
;
96 use std
::io
::{self, Read, Write}
;
97 use std
::iter
::repeat
;
100 use std
::path
::{PathBuf, Path}
;
101 use std
::process
::{self, Command, Stdio}
;
103 use std
::sync
::atomic
::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}
;
104 use std
::sync
::{Once, ONCE_INIT}
;
108 use syntax
::codemap
::{CodeMap, FileLoader, RealFileLoader}
;
109 use syntax
::feature_gate
::{GatedCfg, UnstableFeatures}
;
110 use syntax
::parse
::{self, PResult}
;
111 use syntax_pos
::{hygiene, DUMMY_SP, MultiSpan, FileName}
;
119 mod derive_registrar
;
121 pub mod target_features
{
123 use syntax
::symbol
::Symbol
;
124 use rustc
::session
::Session
;
125 use rustc_codegen_utils
::codegen_backend
::CodegenBackend
;
127 /// Add `target_feature = "..."` cfgs for a variety of platform
128 /// specific features (SSE, NEON etc.).
130 /// This is performed by checking whether a whitelisted set of
131 /// features is available on the target machine, by querying LLVM.
132 pub fn add_configuration(cfg
: &mut ast
::CrateConfig
,
134 codegen_backend
: &CodegenBackend
) {
135 let tf
= Symbol
::intern("target_feature");
137 for feat
in codegen_backend
.target_features(sess
) {
138 cfg
.insert((tf
, Some(feat
)));
141 if sess
.crt_static_feature() {
142 cfg
.insert((tf
, Some(Symbol
::intern("crt-static"))));
147 const BUG_REPORT_URL
: &'
static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
150 const ICE_REPORT_COMPILER_FLAGS
: &'
static [&'
static str] = &[
155 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE
: &'
static [&'
static str] = &[
159 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
: &'
static [&'
static str] = &[
163 pub fn abort_on_err
<T
>(result
: Result
<T
, CompileIncomplete
>, sess
: &Session
) -> T
{
165 Err(CompileIncomplete
::Errored(ErrorReported
)) => {
166 sess
.abort_if_errors();
167 panic
!("error reported but abort_if_errors didn't abort???");
169 Err(CompileIncomplete
::Stopped
) => {
170 sess
.fatal("compilation terminated");
176 pub fn run
<F
>(run_compiler
: F
) -> isize
177 where F
: FnOnce() -> (CompileResult
, Option
<Session
>) + Send
+ '
static
180 let (result
, session
) = run_compiler();
181 if let Err(CompileIncomplete
::Errored(_
)) = result
{
184 sess
.abort_if_errors();
185 panic
!("error reported but abort_if_errors didn't abort???");
189 errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
,
193 let handler
= errors
::Handler
::with_emitter(true, false, Box
::new(emitter
));
194 handler
.emit(&MultiSpan
::new(),
195 "aborting due to previous error(s)",
196 errors
::Level
::Fatal
);
197 panic
::resume_unwind(Box
::new(errors
::FatalErrorMarker
));
205 fn load_backend_from_dylib(path
: &Path
) -> fn() -> Box
<CodegenBackend
> {
206 // Note that we're specifically using `open_global_now` here rather than
207 // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
208 // where NOW means "bind everything right now" because we don't want
209 // surprises later on and RTLD_GLOBAL allows the symbols to be made
210 // available for future dynamic libraries opened. This is currently used by
211 // loading LLVM and then making its symbols available for other dynamic
213 let lib
= match DynamicLibrary
::open_global_now(path
) {
216 let err
= format
!("couldn't load codegen backend {:?}: {:?}",
219 early_error(ErrorOutputType
::default(), &err
);
223 match lib
.symbol("__rustc_codegen_backend") {
226 mem
::transmute
::<*mut u8, _
>(f
)
229 let err
= format
!("couldn't load codegen backend as it \
230 doesn't export the `__rustc_codegen_backend` \
232 early_error(ErrorOutputType
::default(), &err
);
238 pub fn get_codegen_backend(sess
: &Session
) -> Box
<CodegenBackend
> {
239 static INIT
: Once
= ONCE_INIT
;
243 static mut LOAD
: fn() -> Box
<CodegenBackend
> = || unreachable
!();
246 let codegen_name
= sess
.opts
.debugging_opts
.codegen_backend
.as_ref()
247 .unwrap_or(&sess
.target
.target
.options
.codegen_backend
);
248 let backend
= match &codegen_name
[..] {
250 rustc_codegen_utils
::codegen_backend
::MetadataOnlyCodegenBackend
::new
252 filename
if filename
.contains(".") => {
253 load_backend_from_dylib(filename
.as_ref())
255 codegen_name
=> get_codegen_sysroot(codegen_name
),
262 let backend
= unsafe { LOAD() }
;
267 fn get_codegen_sysroot(backend_name
: &str) -> fn() -> Box
<CodegenBackend
> {
268 // For now we only allow this function to be called once as it'll dlopen a
269 // few things, which seems to work best if we only do that once. In
270 // general this assertion never trips due to the once guard in `get_codegen_backend`,
271 // but there's a few manual calls to this function in this file we protect
273 static LOADED
: AtomicBool
= ATOMIC_BOOL_INIT
;
274 assert
!(!LOADED
.fetch_or(true, Ordering
::SeqCst
),
275 "cannot load the default codegen backend twice");
277 // When we're compiling this library with `--test` it'll run as a binary but
278 // not actually exercise much functionality. As a result most of the logic
279 // here is defunkt (it assumes we're a dynamic library in a sysroot) so
280 // let's just return a dummy creation function which won't be used in
283 return rustc_codegen_utils
::codegen_backend
::MetadataOnlyCodegenBackend
::new
286 let target
= session
::config
::host_triple();
287 let mut sysroot_candidates
= vec
![filesearch
::get_or_default_sysroot()];
288 let path
= current_dll_path()
289 .and_then(|s
| s
.canonicalize().ok());
290 if let Some(dll
) = path
{
291 // use `parent` twice to chop off the file name and then also the
292 // directory containing the dll which should be either `lib` or `bin`.
293 if let Some(path
) = dll
.parent().and_then(|p
| p
.parent()) {
294 // The original `path` pointed at the `rustc_driver` crate's dll.
295 // Now that dll should only be in one of two locations. The first is
296 // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
297 // other is the target's libdir, for example
298 // `$sysroot/lib/rustlib/$target/lib/*.dll`.
300 // We don't know which, so let's assume that if our `path` above
301 // ends in `$target` we *could* be in the target libdir, and always
302 // assume that we may be in the main libdir.
303 sysroot_candidates
.push(path
.to_owned());
305 if path
.ends_with(target
) {
306 sysroot_candidates
.extend(path
.parent() // chop off `$target`
307 .and_then(|p
| p
.parent()) // chop off `rustlib`
308 .and_then(|p
| p
.parent()) // chop off `lib`
309 .map(|s
| s
.to_owned()));
314 let sysroot
= sysroot_candidates
.iter()
316 let libdir
= filesearch
::relative_target_lib_path(&sysroot
, &target
);
318 .with_file_name(option_env
!("CFG_CODEGEN_BACKENDS_DIR")
319 .unwrap_or("codegen-backends"))
322 info
!("codegen backend candidate: {}", f
.display());
326 let sysroot
= match sysroot
{
329 let candidates
= sysroot_candidates
.iter()
330 .map(|p
| p
.display().to_string())
333 let err
= format
!("failed to find a `codegen-backends` folder \
334 in the sysroot candidates:\n* {}", candidates
);
335 early_error(ErrorOutputType
::default(), &err
);
338 info
!("probing {} for a codegen backend", sysroot
.display());
340 let d
= match sysroot
.read_dir() {
343 let err
= format
!("failed to load default codegen backend, couldn't \
344 read `{}`: {}", sysroot
.display(), e
);
345 early_error(ErrorOutputType
::default(), &err
);
349 let mut file
: Option
<PathBuf
> = None
;
351 let expected_name
= format
!("rustc_codegen_llvm-{}", backend_name
);
352 for entry
in d
.filter_map(|e
| e
.ok()) {
353 let path
= entry
.path();
354 let filename
= match path
.file_name().and_then(|s
| s
.to_str()) {
358 if !(filename
.starts_with(DLL_PREFIX
) && filename
.ends_with(DLL_SUFFIX
)) {
361 let name
= &filename
[DLL_PREFIX
.len() .. filename
.len() - DLL_SUFFIX
.len()];
362 if name
!= expected_name
{
365 if let Some(ref prev
) = file
{
366 let err
= format
!("duplicate codegen backends found\n\
369 ", prev
.display(), path
.display());
370 early_error(ErrorOutputType
::default(), &err
);
372 file
= Some(path
.clone());
376 Some(ref s
) => return load_backend_from_dylib(s
),
378 let err
= format
!("failed to load default codegen backend for `{}`, \
379 no appropriate codegen dylib found in `{}`",
380 backend_name
, sysroot
.display());
381 early_error(ErrorOutputType
::default(), &err
);
386 fn current_dll_path() -> Option
<PathBuf
> {
387 use std
::ffi
::{OsStr, CStr}
;
388 use std
::os
::unix
::prelude
::*;
391 let addr
= current_dll_path
as usize as *mut _
;
392 let mut info
= mem
::zeroed();
393 if libc
::dladdr(addr
, &mut info
) == 0 {
394 info
!("dladdr failed");
397 if info
.dli_fname
.is_null() {
398 info
!("dladdr returned null pointer");
401 let bytes
= CStr
::from_ptr(info
.dli_fname
).to_bytes();
402 let os
= OsStr
::from_bytes(bytes
);
403 Some(PathBuf
::from(os
))
408 fn current_dll_path() -> Option
<PathBuf
> {
409 use std
::ffi
::OsString
;
410 use std
::os
::windows
::prelude
::*;
413 fn GetModuleHandleExW(dwFlags
: u32,
415 phModule
: *mut usize) -> i32;
416 fn GetModuleFileNameW(hModule
: usize,
417 lpFilename
: *mut u16,
421 const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
: u32 = 0x00000004;
425 let r
= GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
426 current_dll_path
as usize,
429 info
!("GetModuleHandleExW failed: {}", io
::Error
::last_os_error());
432 let mut space
= Vec
::with_capacity(1024);
433 let r
= GetModuleFileNameW(module
,
435 space
.capacity() as u32);
437 info
!("GetModuleFileNameW failed: {}", io
::Error
::last_os_error());
441 if r
>= space
.capacity() {
442 info
!("our buffer was too small? {}",
443 io
::Error
::last_os_error());
447 let os
= OsString
::from_wide(&space
);
448 Some(PathBuf
::from(os
))
453 // Parse args and run the compiler. This is the primary entry point for rustc.
454 // See comments on CompilerCalls below for details about the callbacks argument.
455 // The FileLoader provides a way to load files from sources other than the file system.
456 pub fn run_compiler
<'a
>(args
: &[String
],
457 callbacks
: Box
<CompilerCalls
<'a
> + sync
::Send
+ 'a
>,
458 file_loader
: Option
<Box
<FileLoader
+ Send
+ Sync
+ '
static>>,
459 emitter_dest
: Option
<Box
<Write
+ Send
>>)
460 -> (CompileResult
, Option
<Session
>)
462 syntax
::with_globals(|| {
463 let matches
= match handle_options(args
) {
464 Some(matches
) => matches
,
465 None
=> return (Ok(()), None
),
468 let (sopts
, cfg
) = config
::build_session_options_and_crate_config(&matches
);
469 hygiene
::set_default_edition(sopts
.edition
);
471 driver
::spawn_thread_pool(sopts
, |sopts
| {
472 run_compiler_with_pool(matches
, sopts
, cfg
, callbacks
, file_loader
, emitter_dest
)
477 fn run_compiler_with_pool
<'a
>(
478 matches
: getopts
::Matches
,
479 sopts
: config
::Options
,
480 cfg
: ast
::CrateConfig
,
481 mut callbacks
: Box
<CompilerCalls
<'a
> + sync
::Send
+ 'a
>,
482 file_loader
: Option
<Box
<FileLoader
+ Send
+ Sync
+ '
static>>,
483 emitter_dest
: Option
<Box
<Write
+ Send
>>
484 ) -> (CompileResult
, Option
<Session
>) {
485 macro_rules
! do_or_return
{($expr
: expr
, $sess
: expr
) => {
487 Compilation
::Stop
=> return (Ok(()), $sess
),
488 Compilation
::Continue
=> {}
492 let descriptions
= diagnostics_registry();
494 do_or_return
!(callbacks
.early_callback(&matches
,
501 let (odir
, ofile
) = make_output(&matches
);
502 let (input
, input_file_path
, input_err
) = match make_input(&matches
.free
) {
503 Some((input
, input_file_path
, input_err
)) => {
504 let (input
, input_file_path
) = callbacks
.some_input(input
, input_file_path
);
505 (input
, input_file_path
, input_err
)
507 None
=> match callbacks
.no_input(&matches
, &sopts
, &cfg
, &odir
, &ofile
, &descriptions
) {
508 Some((input
, input_file_path
)) => (input
, input_file_path
, None
),
509 None
=> return (Ok(()), None
),
513 let loader
= file_loader
.unwrap_or(box RealFileLoader
);
514 let codemap
= Lrc
::new(CodeMap
::with_file_loader(loader
, sopts
.file_path_mapping()));
515 let mut sess
= session
::build_session_with_codemap(
516 sopts
, input_file_path
.clone(), descriptions
, codemap
, emitter_dest
,
519 if let Some(err
) = input_err
{
520 // Immediately stop compilation if there was an issue reading
521 // the input (for example if the input stream is not UTF-8).
522 sess
.err(&format
!("{}", err
));
523 return (Err(CompileIncomplete
::Stopped
), Some(sess
));
526 let codegen_backend
= get_codegen_backend(&sess
);
528 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
530 let mut cfg
= config
::build_configuration(&sess
, cfg
);
531 target_features
::add_configuration(&mut cfg
, &sess
, &*codegen_backend
);
532 sess
.parse_sess
.config
= cfg
;
535 let plugins
= sess
.opts
.debugging_opts
.extra_plugins
.clone();
537 let cstore
= CStore
::new(codegen_backend
.metadata_loader());
539 do_or_return
!(callbacks
.late_callback(&*codegen_backend
,
545 &ofile
), Some(sess
));
547 let _sess_abort_error
= OnDrop(|| sess
.diagnostic().print_error_count());
549 let control
= callbacks
.build_controller(&sess
, &matches
);
551 driver
::compile_input(codegen_backend
,
566 pub fn set_sigpipe_handler() {
568 // Set the SIGPIPE signal handler, so that an EPIPE
569 // will cause rustc to terminate, as expected.
570 assert
!(libc
::signal(libc
::SIGPIPE
, libc
::SIG_DFL
) != libc
::SIG_ERR
);
575 pub fn set_sigpipe_handler() {}
577 // Extract output directory and file from matches.
578 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
579 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
580 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
584 // Extract input (string or file and optional path) from matches.
585 fn make_input(free_matches
: &[String
]) -> Option
<(Input
, Option
<PathBuf
>, Option
<io
::Error
>)> {
586 if free_matches
.len() == 1 {
587 let ifile
= &free_matches
[0];
589 let mut src
= String
::new();
590 let err
= if io
::stdin().read_to_string(&mut src
).is_err() {
591 Some(io
::Error
::new(io
::ErrorKind
::InvalidData
,
592 "couldn't read from stdin, as it did not contain valid UTF-8"))
596 Some((Input
::Str { name: FileName::Anon, input: src }
,
599 Some((Input
::File(PathBuf
::from(ifile
)),
600 Some(PathBuf
::from(ifile
)), None
))
607 fn parse_pretty(sess
: &Session
,
608 matches
: &getopts
::Matches
)
609 -> Option
<(PpMode
, Option
<UserIdentifiedItem
>)> {
610 let pretty
= if sess
.opts
.debugging_opts
.unstable_options
{
611 matches
.opt_default("pretty", "normal").map(|a
| {
612 // stable pretty-print variants only
613 pretty
::parse_pretty(sess
, &a
, false)
619 if pretty
.is_none() {
620 sess
.opts
.debugging_opts
.unpretty
.as_ref().map(|a
| {
621 // extended with unstable pretty-print variants
622 pretty
::parse_pretty(sess
, &a
, true)
629 // Whether to stop or continue compilation.
630 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
631 pub enum Compilation
{
637 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
639 Compilation
::Stop
=> Compilation
::Stop
,
640 Compilation
::Continue
=> next(),
645 /// A trait for customising the compilation process. Offers a number of hooks for
646 /// executing custom code or customising input.
647 pub trait CompilerCalls
<'a
> {
648 /// Hook for a callback early in the process of handling arguments. This will
649 /// be called straight after options have been parsed but before anything
650 /// else (e.g., selecting input and output).
651 fn early_callback(&mut self,
652 _
: &getopts
::Matches
,
654 _
: &ast
::CrateConfig
,
655 _
: &errors
::registry
::Registry
,
658 Compilation
::Continue
661 /// Hook for a callback late in the process of handling arguments. This will
662 /// be called just before actual compilation starts (and before build_controller
663 /// is called), after all arguments etc. have been completely handled.
664 fn late_callback(&mut self,
666 _
: &getopts
::Matches
,
673 Compilation
::Continue
676 /// Called after we extract the input from the arguments. Gives the implementer
677 /// an opportunity to change the inputs or to add some custom input handling.
678 /// The default behaviour is to simply pass through the inputs.
679 fn some_input(&mut self,
681 input_path
: Option
<PathBuf
>)
682 -> (Input
, Option
<PathBuf
>) {
686 /// Called after we extract the input from the arguments if there is no valid
687 /// input. Gives the implementer an opportunity to supply alternate input (by
688 /// returning a Some value) or to add custom behaviour for this error such as
689 /// emitting error messages. Returning None will cause compilation to stop
691 fn no_input(&mut self,
692 _
: &getopts
::Matches
,
694 _
: &ast
::CrateConfig
,
697 _
: &errors
::registry
::Registry
)
698 -> Option
<(Input
, Option
<PathBuf
>)> {
702 // Create a CompilController struct for controlling the behaviour of
708 ) -> CompileController
<'a
>;
711 /// CompilerCalls instance for a regular rustc build.
712 #[derive(Copy, Clone)]
713 pub struct RustcDefaultCalls
;
715 // FIXME remove these and use winapi 0.3 instead
716 // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
718 fn stdout_isatty() -> bool
{
719 unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
723 fn stdout_isatty() -> bool
{
726 type HANDLE
= *mut u8;
727 type LPDWORD
= *mut u32;
728 const STD_OUTPUT_HANDLE
: DWORD
= -11i32 as DWORD
;
730 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
731 fn GetConsoleMode(hConsoleHandle
: HANDLE
, lpMode
: LPDWORD
) -> BOOL
;
734 let handle
= GetStdHandle(STD_OUTPUT_HANDLE
);
736 GetConsoleMode(handle
, &mut out
) != 0
740 fn handle_explain(code
: &str,
741 descriptions
: &errors
::registry
::Registry
,
742 output
: ErrorOutputType
) {
743 let normalised
= if code
.starts_with("E") {
746 format
!("E{0:0>4}", code
)
748 match descriptions
.find_description(&normalised
) {
749 Some(ref description
) => {
750 let mut is_in_code_block
= false;
751 let mut text
= String
::new();
753 // Slice off the leading newline and print.
754 for line
in description
[1..].lines() {
755 let indent_level
= line
.find(|c
: char| !c
.is_whitespace())
756 .unwrap_or_else(|| line
.len());
757 let dedented_line
= &line
[indent_level
..];
758 if dedented_line
.starts_with("```") {
759 is_in_code_block
= !is_in_code_block
;
760 text
.push_str(&line
[..(indent_level
+3)]);
761 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
770 show_content_with_pager(&text
);
776 early_error(output
, &format
!("no extended information for {}", code
));
781 fn show_content_with_pager(content
: &String
) {
782 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| if cfg
!(windows
) {
783 OsString
::from("more.com")
785 OsString
::from("less")
788 let mut fallback_to_println
= false;
790 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
792 if let Some(pipe
) = pager
.stdin
.as_mut() {
793 if pipe
.write_all(content
.as_bytes()).is_err() {
794 fallback_to_println
= true;
798 if pager
.wait().is_err() {
799 fallback_to_println
= true;
803 fallback_to_println
= true;
807 // If pager fails for whatever reason, we should still print the content
808 // to standard output
809 if fallback_to_println
{
810 print
!("{}", content
);
814 impl<'a
> CompilerCalls
<'a
> for RustcDefaultCalls
{
815 fn early_callback(&mut self,
816 matches
: &getopts
::Matches
,
818 _
: &ast
::CrateConfig
,
819 descriptions
: &errors
::registry
::Registry
,
820 output
: ErrorOutputType
)
822 if let Some(ref code
) = matches
.opt_str("explain") {
823 handle_explain(code
, descriptions
, output
);
824 return Compilation
::Stop
;
827 Compilation
::Continue
830 fn no_input(&mut self,
831 matches
: &getopts
::Matches
,
832 sopts
: &config
::Options
,
833 cfg
: &ast
::CrateConfig
,
834 odir
: &Option
<PathBuf
>,
835 ofile
: &Option
<PathBuf
>,
836 descriptions
: &errors
::registry
::Registry
)
837 -> Option
<(Input
, Option
<PathBuf
>)> {
838 match matches
.free
.len() {
840 let mut sess
= build_session(sopts
.clone(),
842 descriptions
.clone());
843 if sopts
.describe_lints
{
844 let mut ls
= lint
::LintStore
::new();
845 rustc_lint
::register_builtins(&mut ls
, Some(&sess
));
846 describe_lints(&sess
, &ls
, false);
849 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
850 let mut cfg
= config
::build_configuration(&sess
, cfg
.clone());
851 let codegen_backend
= get_codegen_backend(&sess
);
852 target_features
::add_configuration(&mut cfg
, &sess
, &*codegen_backend
);
853 sess
.parse_sess
.config
= cfg
;
854 let should_stop
= RustcDefaultCalls
::print_crate_info(
862 if should_stop
== Compilation
::Stop
{
865 early_error(sopts
.error_format
, "no input filename given");
867 1 => panic
!("make_input should have provided valid inputs"),
868 _
=> early_error(sopts
.error_format
, "multiple input filenames provided"),
872 fn late_callback(&mut self,
873 codegen_backend
: &CodegenBackend
,
874 matches
: &getopts
::Matches
,
878 odir
: &Option
<PathBuf
>,
879 ofile
: &Option
<PathBuf
>)
881 RustcDefaultCalls
::print_crate_info(codegen_backend
, sess
, Some(input
), odir
, ofile
)
882 .and_then(|| RustcDefaultCalls
::list_metadata(sess
, cstore
, matches
, input
))
885 fn build_controller(self: Box
<Self>,
887 matches
: &getopts
::Matches
)
888 -> CompileController
<'a
> {
889 let mut control
= CompileController
::basic();
891 control
.keep_ast
= sess
.opts
.debugging_opts
.keep_ast
;
892 control
.continue_parse_after_error
= sess
.opts
.debugging_opts
.continue_parse_after_error
;
894 if let Some((ppm
, opt_uii
)) = parse_pretty(sess
, matches
) {
895 if ppm
.needs_ast_map(&opt_uii
) {
896 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
898 control
.after_parse
.callback
= box move |state
| {
899 state
.krate
= Some(pretty
::fold_crate(state
.session
,
900 state
.krate
.take().unwrap(),
903 control
.after_hir_lowering
.callback
= box move |state
| {
904 pretty
::print_after_hir_lowering(state
.session
,
905 state
.cstore
.unwrap(),
906 state
.hir_map
.unwrap(),
907 state
.analysis
.unwrap(),
908 state
.resolutions
.unwrap(),
910 &state
.expanded_crate
.take().unwrap(),
911 state
.crate_name
.unwrap(),
913 state
.arenas
.unwrap(),
914 state
.output_filenames
.unwrap(),
919 control
.after_parse
.stop
= Compilation
::Stop
;
921 control
.after_parse
.callback
= box move |state
| {
922 let krate
= pretty
::fold_crate(state
.session
, state
.krate
.take().unwrap(), ppm
);
923 pretty
::print_after_parsing(state
.session
,
934 if sess
.opts
.debugging_opts
.parse_only
||
935 sess
.opts
.debugging_opts
.show_span
.is_some() ||
936 sess
.opts
.debugging_opts
.ast_json_noexpand
{
937 control
.after_parse
.stop
= Compilation
::Stop
;
940 if sess
.opts
.debugging_opts
.no_analysis
||
941 sess
.opts
.debugging_opts
.ast_json
{
942 control
.after_hir_lowering
.stop
= Compilation
::Stop
;
945 if sess
.opts
.debugging_opts
.save_analysis
{
946 enable_save_analysis(&mut control
);
949 if sess
.print_fuel_crate
.is_some() {
950 let old_callback
= control
.compilation_done
.callback
;
951 control
.compilation_done
.callback
= box move |state
| {
953 let sess
= state
.session
;
954 println
!("Fuel used by {}: {}",
955 sess
.print_fuel_crate
.as_ref().unwrap(),
956 sess
.print_fuel
.get());
963 pub fn enable_save_analysis(control
: &mut CompileController
) {
964 control
.keep_ast
= true;
965 control
.after_analysis
.callback
= box |state
| {
966 time(state
.session
, "save analysis", || {
967 save
::process_crate(state
.tcx
.unwrap(),
968 state
.expanded_crate
.unwrap(),
969 state
.analysis
.unwrap(),
970 state
.crate_name
.unwrap(),
972 DumpHandler
::new(state
.out_dir
,
973 state
.crate_name
.unwrap()))
976 control
.after_analysis
.run_callback_on_error
= true;
977 control
.make_glob_map
= resolve
::MakeGlobMap
::Yes
;
980 impl RustcDefaultCalls
{
981 pub fn list_metadata(sess
: &Session
,
983 matches
: &getopts
::Matches
,
986 let r
= matches
.opt_strs("Z");
987 if r
.contains(&("ls".to_string())) {
989 &Input
::File(ref ifile
) => {
990 let path
= &(*ifile
);
991 let mut v
= Vec
::new();
992 locator
::list_file_metadata(&sess
.target
.target
,
994 cstore
.metadata_loader(),
997 println
!("{}", String
::from_utf8(v
).unwrap());
999 &Input
::Str { .. }
=> {
1000 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
1003 return Compilation
::Stop
;
1006 return Compilation
::Continue
;
1010 fn print_crate_info(codegen_backend
: &CodegenBackend
,
1012 input
: Option
<&Input
>,
1013 odir
: &Option
<PathBuf
>,
1014 ofile
: &Option
<PathBuf
>)
1016 use rustc
::session
::config
::PrintRequest
::*;
1017 // PrintRequest::NativeStaticLibs is special - printed during linking
1018 // (empty iterator returns true)
1019 if sess
.opts
.prints
.iter().all(|&p
| p
==PrintRequest
::NativeStaticLibs
) {
1020 return Compilation
::Continue
;
1023 let attrs
= match input
{
1026 let result
= parse_crate_attrs(sess
, input
);
1028 Ok(attrs
) => Some(attrs
),
1029 Err(mut parse_error
) => {
1031 return Compilation
::Stop
;
1036 for req
in &sess
.opts
.prints
{
1039 let mut targets
= rustc_target
::spec
::get_targets().collect
::<Vec
<String
>>();
1041 println
!("{}", targets
.join("\n"));
1043 Sysroot
=> println
!("{}", sess
.sysroot().display()),
1044 TargetSpec
=> println
!("{}", sess
.target
.target
.to_json().pretty()),
1045 FileNames
| CrateName
=> {
1046 let input
= match input
{
1047 Some(input
) => input
,
1048 None
=> early_error(ErrorOutputType
::default(), "no input file provided"),
1050 let attrs
= attrs
.as_ref().unwrap();
1051 let t_outputs
= driver
::build_output_filenames(input
, odir
, ofile
, attrs
, sess
);
1052 let id
= rustc_codegen_utils
::link
::find_crate_name(Some(sess
), attrs
, input
);
1053 if *req
== PrintRequest
::CrateName
{
1057 let crate_types
= driver
::collect_crate_types(sess
, attrs
);
1058 for &style
in &crate_types
{
1059 let fname
= rustc_codegen_utils
::link
::filename_for_input(
1068 .to_string_lossy());
1072 let allow_unstable_cfg
= UnstableFeatures
::from_environment()
1073 .is_nightly_build();
1075 let mut cfgs
= Vec
::new();
1076 for &(name
, ref value
) in sess
.parse_sess
.config
.iter() {
1077 let gated_cfg
= GatedCfg
::gate(&ast
::MetaItem
{
1078 ident
: ast
::Path
::from_ident(name
.to_ident()),
1079 node
: ast
::MetaItemKind
::Word
,
1083 // Note that crt-static is a specially recognized cfg
1084 // directive that's printed out here as part of
1085 // rust-lang/rust#37406, but in general the
1086 // `target_feature` cfg is gated under
1087 // rust-lang/rust#29717. For now this is just
1088 // specifically allowing the crt-static cfg and that's
1089 // it, this is intended to get into Cargo and then go
1090 // through to build scripts.
1091 let value
= value
.as_ref().map(|s
| s
.as_str());
1092 let value
= value
.as_ref().map(|s
| s
.as_ref());
1093 if name
!= "target_feature" || value
!= Some("crt-static") {
1094 if !allow_unstable_cfg
&& gated_cfg
.is_some() {
1099 cfgs
.push(if let Some(value
) = value
{
1100 format
!("{}=\"{}\"", name
, value
)
1108 println
!("{}", cfg
);
1111 RelocationModels
| CodeModels
| TlsModels
| TargetCPUs
| TargetFeatures
=> {
1112 codegen_backend
.print(*req
, sess
);
1114 // Any output here interferes with Cargo's parsing of other printed output
1115 PrintRequest
::NativeStaticLibs
=> {}
1118 return Compilation
::Stop
;
1122 /// Returns a version string such as "0.12.0-dev".
1123 fn release_str() -> Option
<&'
static str> {
1124 option_env
!("CFG_RELEASE")
1127 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
1128 fn commit_hash_str() -> Option
<&'
static str> {
1129 option_env
!("CFG_VER_HASH")
1132 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
1133 fn commit_date_str() -> Option
<&'
static str> {
1134 option_env
!("CFG_VER_DATE")
1137 /// Prints version information
1138 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
1139 let verbose
= matches
.opt_present("verbose");
1143 option_env
!("CFG_VERSION").unwrap_or("unknown version"));
1145 fn unw(x
: Option
<&str>) -> &str {
1146 x
.unwrap_or("unknown")
1148 println
!("binary: {}", binary
);
1149 println
!("commit-hash: {}", unw(commit_hash_str()));
1150 println
!("commit-date: {}", unw(commit_date_str()));
1151 println
!("host: {}", config
::host_triple());
1152 println
!("release: {}", unw(release_str()));
1153 get_codegen_sysroot("llvm")().print_version();
1157 fn usage(verbose
: bool
, include_unstable_options
: bool
) {
1158 let groups
= if verbose
{
1159 config
::rustc_optgroups()
1161 config
::rustc_short_optgroups()
1163 let mut options
= getopts
::Options
::new();
1164 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
1165 (option
.apply
)(&mut options
);
1167 let message
= format
!("Usage: rustc [OPTIONS] INPUT");
1168 let nightly_help
= if nightly_options
::is_nightly_build() {
1169 "\n -Z help Print internal options for debugging rustc"
1173 let verbose_help
= if verbose
{
1176 "\n --help -v Print the full set of options rustc accepts"
1178 println
!("{}\nAdditional help:
1179 -C help Print codegen options
1181 Print 'lint' options and default settings{}{}\n",
1182 options
.usage(&message
),
1187 fn print_wall_help() {
1189 The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
1190 default. Use `rustc -W help` to see all available lints. It's more common to put
1191 warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
1192 the command line flag directly.
1196 fn describe_lints(sess
: &Session
, lint_store
: &lint
::LintStore
, loaded_plugins
: bool
) {
1198 Available lint options:
1199 -W <foo> Warn about <foo>
1203 -F <foo> Forbid <foo> \
1204 (deny <foo> and all attempts to override)
1208 fn sort_lints(sess
: &Session
, lints
: Vec
<(&'
static Lint
, bool
)>) -> Vec
<&'
static Lint
> {
1209 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, _
)| x
).collect();
1210 // The sort doesn't case-fold but it's doubtful we care.
1211 lints
.sort_by_cached_key(|x
: &&Lint
| (x
.default_level(sess
), x
.name
));
1215 fn sort_lint_groups(lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>, bool
)>)
1216 -> Vec
<(&'
static str, Vec
<lint
::LintId
>)> {
1217 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
1218 lints
.sort_by(|&(x
, _
): &(&'
static str, Vec
<lint
::LintId
>),
1219 &(y
, _
): &(&'
static str, Vec
<lint
::LintId
>)| {
1225 let (plugin
, builtin
): (Vec
<_
>, _
) = lint_store
.get_lints()
1228 .partition(|&(_
, p
)| p
);
1229 let plugin
= sort_lints(sess
, plugin
);
1230 let builtin
= sort_lints(sess
, builtin
);
1232 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) = lint_store
.get_lint_groups()
1235 .partition(|&(.., p
)| p
);
1236 let plugin_groups
= sort_lint_groups(plugin_groups
);
1237 let builtin_groups
= sort_lint_groups(builtin_groups
);
1239 let max_name_len
= plugin
.iter()
1241 .map(|&s
| s
.name
.chars().count())
1244 let padded
= |x
: &str| {
1245 let mut s
= repeat(" ")
1246 .take(max_name_len
- x
.chars().count())
1247 .collect
::<String
>();
1252 println
!("Lint checks provided by rustc:\n");
1253 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
1254 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
1256 let print_lints
= |lints
: Vec
<&Lint
>| {
1258 let name
= lint
.name_lower().replace("_", "-");
1259 println
!(" {} {:7.7} {}",
1261 lint
.default_level
.as_str(),
1267 print_lints(builtin
);
1271 let max_name_len
= max("warnings".len(),
1272 plugin_groups
.iter()
1273 .chain(&builtin_groups
)
1274 .map(|&(s
, _
)| s
.chars().count())
1278 let padded
= |x
: &str| {
1279 let mut s
= repeat(" ")
1280 .take(max_name_len
- x
.chars().count())
1281 .collect
::<String
>();
1286 println
!("Lint groups provided by rustc:\n");
1287 println
!(" {} {}", padded("name"), "sub-lints");
1288 println
!(" {} {}", padded("----"), "---------");
1289 println
!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
1291 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<lint
::LintId
>)>| {
1292 for (name
, to
) in lints
{
1293 let name
= name
.to_lowercase().replace("_", "-");
1294 let desc
= to
.into_iter()
1295 .map(|x
| x
.to_string().replace("_", "-"))
1296 .collect
::<Vec
<String
>>()
1298 println
!(" {} {}", padded(&name
), desc
);
1303 print_lint_groups(builtin_groups
);
1305 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
1306 (false, 0, _
) | (false, _
, 0) => {
1307 println
!("Compiler plugins can provide additional lints and lint groups. To see a \
1308 listing of these, re-run `rustc -W help` with a crate filename.");
1310 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
1311 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
1314 println
!("Lint checks provided by plugins loaded by this crate:\n");
1315 print_lints(plugin
);
1318 println
!("Lint groups provided by plugins loaded by this crate:\n");
1319 print_lint_groups(plugin_groups
);
1325 fn describe_debug_flags() {
1326 println
!("\nAvailable debug options:\n");
1327 print_flag_list("-Z", config
::DB_OPTIONS
);
1330 fn describe_codegen_flags() {
1331 println
!("\nAvailable codegen options:\n");
1332 print_flag_list("-C", config
::CG_OPTIONS
);
1335 fn print_flag_list
<T
>(cmdline_opt
: &str,
1336 flag_list
: &[(&'
static str, T
, Option
<&'
static str>, &'
static str)]) {
1337 let max_len
= flag_list
.iter()
1338 .map(|&(name
, _
, opt_type_desc
, _
)| {
1339 let extra_len
= match opt_type_desc
{
1343 name
.chars().count() + extra_len
1348 for &(name
, _
, opt_type_desc
, desc
) in flag_list
{
1349 let (width
, extra
) = match opt_type_desc
{
1350 Some(..) => (max_len
- 4, "=val"),
1351 None
=> (max_len
, ""),
1353 println
!(" {} {:>width$}{} -- {}",
1355 name
.replace("_", "-"),
1362 /// Process command line options. Emits messages as appropriate. If compilation
1363 /// should continue, returns a getopts::Matches object parsed from args,
1364 /// otherwise returns None.
1366 /// The compiler's handling of options is a little complicated as it ties into
1367 /// our stability story, and it's even *more* complicated by historical
1368 /// accidents. The current intention of each compiler option is to have one of
1371 /// 1. An option is stable and can be used everywhere.
1372 /// 2. An option is unstable, but was historically allowed on the stable
1374 /// 3. An option is unstable, and can only be used on nightly.
1376 /// Like unstable library and language features, however, unstable options have
1377 /// always required a form of "opt in" to indicate that you're using them. This
1378 /// provides the easy ability to scan a code base to check to see if anything
1379 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
1381 /// All options behind `-Z` are considered unstable by default. Other top-level
1382 /// options can also be considered unstable, and they were unlocked through the
1383 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
1384 /// instability in both cases, though.
1386 /// So with all that in mind, the comments below have some more detail about the
1387 /// contortions done here to get things to work out correctly.
1388 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
1389 // Throw away the first argument, the name of the binary
1390 let args
= &args
[1..];
1392 if args
.is_empty() {
1393 // user did not write `-v` nor `-Z unstable-options`, so do not
1394 // include that extra information.
1395 usage(false, false);
1399 // Parse with *all* options defined in the compiler, we don't worry about
1400 // option stability here we just want to parse as much as possible.
1401 let mut options
= getopts
::Options
::new();
1402 for option
in config
::rustc_optgroups() {
1403 (option
.apply
)(&mut options
);
1405 let matches
= match options
.parse(args
) {
1407 Err(f
) => early_error(ErrorOutputType
::default(), &f
.to_string()),
1410 // For all options we just parsed, we check a few aspects:
1412 // * If the option is stable, we're all good
1413 // * If the option wasn't passed, we're all good
1414 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1415 // ourselves), then we require the `-Z unstable-options` flag to unlock
1416 // this option that was passed.
1417 // * If we're a nightly compiler, then unstable options are now unlocked, so
1418 // we're good to go.
1419 // * Otherwise, if we're a truly unstable option then we generate an error
1420 // (unstable option being used on stable)
1421 // * If we're a historically stable-but-should-be-unstable option then we
1422 // emit a warning that we're going to turn this into an error soon.
1423 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1425 if matches
.opt_present("h") || matches
.opt_present("help") {
1426 // Only show unstable options in --help if we *really* accept unstable
1427 // options, which catches the case where we got `-Z unstable-options` on
1428 // the stable channel of Rust which was accidentally allowed
1430 usage(matches
.opt_present("verbose"),
1431 nightly_options
::is_unstable_enabled(&matches
));
1435 // Handle the special case of -Wall.
1436 let wall
= matches
.opt_strs("W");
1437 if wall
.iter().any(|x
| *x
== "all") {
1442 // Don't handle -W help here, because we might first load plugins.
1443 let r
= matches
.opt_strs("Z");
1444 if r
.iter().any(|x
| *x
== "help") {
1445 describe_debug_flags();
1449 let cg_flags
= matches
.opt_strs("C");
1450 if cg_flags
.iter().any(|x
| *x
== "help") {
1451 describe_codegen_flags();
1455 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1456 early_warn(ErrorOutputType
::default(),
1457 "the --no-stack-check flag is deprecated and does nothing");
1460 if cg_flags
.contains(&"passes=list".to_string()) {
1461 get_codegen_sysroot("llvm")().print_passes();
1465 if matches
.opt_present("version") {
1466 version("rustc", &matches
);
1473 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1475 Input
::File(ref ifile
) => {
1476 parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
)
1478 Input
::Str { ref name, ref input }
=> {
1479 parse
::parse_crate_attrs_from_source_str(name
.clone(),
1486 /// Runs `f` in a suitable thread for running `rustc`; returns a
1487 /// `Result` with either the return value of `f` or -- if a panic
1488 /// occurs -- the panic value.
1489 pub fn in_rustc_thread
<F
, R
>(f
: F
) -> Result
<R
, Box
<Any
+ Send
>>
1490 where F
: FnOnce() -> R
+ Send
+ '
static,
1493 // Temporarily have stack size set to 16MB to deal with nom-using crates failing
1494 const STACK_SIZE
: usize = 16 * 1024 * 1024; // 16MB
1497 let spawn_thread
= unsafe {
1498 // Fetch the current resource limits
1499 let mut rlim
= libc
::rlimit
{
1503 if libc
::getrlimit(libc
::RLIMIT_STACK
, &mut rlim
) != 0 {
1504 let err
= io
::Error
::last_os_error();
1505 error
!("in_rustc_thread: error calling getrlimit: {}", err
);
1507 } else if rlim
.rlim_max
< STACK_SIZE
as libc
::rlim_t
{
1510 std
::rt
::deinit_stack_guard();
1511 rlim
.rlim_cur
= STACK_SIZE
as libc
::rlim_t
;
1512 if libc
::setrlimit(libc
::RLIMIT_STACK
, &mut rlim
) != 0 {
1513 let err
= io
::Error
::last_os_error();
1514 error
!("in_rustc_thread: error calling setrlimit: {}", err
);
1515 std
::rt
::update_stack_guard();
1518 std
::rt
::update_stack_guard();
1524 // We set the stack size at link time. See src/rustc/rustc.rs.
1526 let spawn_thread
= false;
1528 #[cfg(not(any(windows,unix)))]
1529 let spawn_thread
= true;
1531 // The or condition is added from backward compatibility.
1532 if spawn_thread
|| env
::var_os("RUST_MIN_STACK").is_some() {
1533 let mut cfg
= thread
::Builder
::new().name("rustc".to_string());
1535 // FIXME: Hacks on hacks. If the env is trying to override the stack size
1536 // then *don't* set it explicitly.
1537 if env
::var_os("RUST_MIN_STACK").is_none() {
1538 cfg
= cfg
.stack_size(STACK_SIZE
);
1541 let thread
= cfg
.spawn(f
);
1542 thread
.unwrap().join()
1544 let f
= panic
::AssertUnwindSafe(f
);
1545 panic
::catch_unwind(f
)
1549 /// Get a list of extra command-line flags provided by the user, as strings.
1551 /// This function is used during ICEs to show more information useful for
1552 /// debugging, since some ICEs only happens with non-default compiler flags
1553 /// (and the users don't always report them).
1554 fn extra_compiler_flags() -> Option
<(Vec
<String
>, bool
)> {
1555 let mut args
= Vec
::new();
1556 for arg
in env
::args_os() {
1557 args
.push(arg
.to_string_lossy().to_string());
1560 // Avoid printing help because of empty args. This can suggest the compiler
1561 // itself is not the program root (consider RLS).
1566 let matches
= if let Some(matches
) = handle_options(&args
) {
1572 let mut result
= Vec
::new();
1573 let mut excluded_cargo_defaults
= false;
1574 for flag
in ICE_REPORT_COMPILER_FLAGS
{
1575 let prefix
= if flag
.len() == 1 { "-" }
else { "--" }
;
1577 for content
in &matches
.opt_strs(flag
) {
1578 // Split always returns the first element
1579 let name
= if let Some(first
) = content
.split('
='
).next() {
1585 let content
= if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
.contains(&name
) {
1591 if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE
.contains(&name
) {
1592 result
.push(format
!("{}{} {}", prefix
, flag
, content
));
1594 excluded_cargo_defaults
= true;
1599 if result
.len() > 0 {
1600 Some((result
, excluded_cargo_defaults
))
1606 /// Run a procedure which will detect panics in the compiler and print nicer
1607 /// error messages rather than just failing the test.
1609 /// The diagnostic emitter yielded to the procedure should be used for reporting
1610 /// errors of the compiler.
1611 pub fn monitor
<F
: FnOnce() + Send
+ '
static>(f
: F
) {
1612 let result
= in_rustc_thread(move || {
1616 if let Err(value
) = result
{
1617 // Thread panicked without emitting a fatal diagnostic
1618 if !value
.is
::<errors
::FatalErrorMarker
>() {
1623 Box
::new(errors
::emitter
::EmitterWriter
::stderr(errors
::ColorConfig
::Auto
,
1627 let handler
= errors
::Handler
::with_emitter(true, false, emitter
);
1629 // a .span_bug or .bug call has already printed what
1630 // it wants to print.
1631 if !value
.is
::<errors
::ExplicitBug
>() {
1632 handler
.emit(&MultiSpan
::new(),
1634 errors
::Level
::Bug
);
1638 "the compiler unexpectedly panicked. this is a bug.".to_string(),
1639 format
!("we would appreciate a bug report: {}", BUG_REPORT_URL
),
1640 format
!("rustc {} running on {}",
1641 option_env
!("CFG_VERSION").unwrap_or("unknown_version"),
1642 config
::host_triple()),
1645 if let Some((flags
, excluded_cargo_defaults
)) = extra_compiler_flags() {
1646 xs
.push(format
!("compiler flags: {}", flags
.join(" ")));
1648 if excluded_cargo_defaults
{
1649 xs
.push("some of the compiler flags provided by cargo are hidden".to_string());
1654 handler
.emit(&MultiSpan
::new(),
1656 errors
::Level
::Note
);
1660 panic
::resume_unwind(Box
::new(errors
::FatalErrorMarker
));
1664 pub fn diagnostics_registry() -> errors
::registry
::Registry
{
1665 use errors
::registry
::Registry
;
1667 let mut all_errors
= Vec
::new();
1668 all_errors
.extend_from_slice(&rustc
::DIAGNOSTICS
);
1669 all_errors
.extend_from_slice(&rustc_typeck
::DIAGNOSTICS
);
1670 all_errors
.extend_from_slice(&rustc_resolve
::DIAGNOSTICS
);
1671 all_errors
.extend_from_slice(&rustc_privacy
::DIAGNOSTICS
);
1672 // FIXME: need to figure out a way to get these back in here
1673 // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics());
1674 all_errors
.extend_from_slice(&rustc_codegen_utils
::DIAGNOSTICS
);
1675 all_errors
.extend_from_slice(&rustc_metadata
::DIAGNOSTICS
);
1676 all_errors
.extend_from_slice(&rustc_passes
::DIAGNOSTICS
);
1677 all_errors
.extend_from_slice(&rustc_plugin
::DIAGNOSTICS
);
1678 all_errors
.extend_from_slice(&rustc_mir
::DIAGNOSTICS
);
1679 all_errors
.extend_from_slice(&syntax
::DIAGNOSTICS
);
1681 Registry
::new(&all_errors
)
1684 /// This allows tools to enable rust logging without having to magically match rustc's
1685 /// log crate version
1686 pub fn init_rustc_env_logger() {
1691 init_rustc_env_logger();
1692 let result
= run(|| {
1693 let args
= env
::args_os().enumerate()
1694 .map(|(i
, arg
)| arg
.into_string().unwrap_or_else(|arg
| {
1695 early_error(ErrorOutputType
::default(),
1696 &format
!("Argument {} is not valid Unicode: {:?}", i
, arg
))
1698 .collect
::<Vec
<_
>>();
1700 Box
::new(RustcDefaultCalls
),
1704 process
::exit(result
as i32);