5 //! This API is completely unstable and subject to change.
7 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
10 #![recursion_limit = "256"]
15 pub extern crate rustc_plugin_impl
as plugin
;
18 use rustc_codegen_ssa
::{traits::CodegenBackend, CodegenResults}
;
19 use rustc_data_structures
::profiling
::{get_resident_set_size, print_time_passes_entry}
;
20 use rustc_data_structures
::sync
::SeqCst
;
21 use rustc_errors
::registry
::{InvalidErrorCode, Registry}
;
22 use rustc_errors
::{ErrorReported, PResult}
;
23 use rustc_feature
::find_gated_cfg
;
24 use rustc_interface
::util
::{self, collect_crate_types, get_codegen_backend}
;
25 use rustc_interface
::{interface, Queries}
;
26 use rustc_lint
::LintStore
;
27 use rustc_metadata
::locator
;
28 use rustc_save_analysis
as save
;
29 use rustc_save_analysis
::DumpHandler
;
30 use rustc_serialize
::json
::{self, ToJson}
;
31 use rustc_session
::config
::{nightly_options, CG_OPTIONS, DB_OPTIONS}
;
32 use rustc_session
::config
::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}
;
33 use rustc_session
::cstore
::MetadataLoader
;
34 use rustc_session
::getopts
;
35 use rustc_session
::lint
::{Lint, LintId}
;
36 use rustc_session
::{config, DiagnosticOutput, Session}
;
37 use rustc_session
::{early_error, early_error_no_abort, early_warn}
;
38 use rustc_span
::source_map
::{FileLoader, FileName}
;
39 use rustc_span
::symbol
::sym
;
43 use std
::default::Default
;
45 use std
::ffi
::OsString
;
47 use std
::io
::{self, Read, Write}
;
48 use std
::lazy
::SyncLazy
;
49 use std
::panic
::{self, catch_unwind}
;
50 use std
::path
::PathBuf
;
51 use std
::process
::{self, Command, Stdio}
;
53 use std
::time
::Instant
;
58 /// Exit status code used for successful compilation and help output.
59 pub const EXIT_SUCCESS
: i32 = 0;
61 /// Exit status code used for compilation failures and invalid flags.
62 pub const EXIT_FAILURE
: i32 = 1;
64 const BUG_REPORT_URL
: &str = "https://github.com/rust-lang/rust/issues/new\
65 ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
67 const ICE_REPORT_COMPILER_FLAGS
: &[&str] = &["Z", "C", "crate-type"];
69 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE
: &[&str] = &["metadata", "extra-filename"];
71 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
: &[&str] = &["incremental"];
73 pub fn abort_on_err
<T
>(result
: Result
<T
, ErrorReported
>, sess
: &Session
) -> T
{
76 sess
.abort_if_errors();
77 panic
!("error reported but abort_if_errors didn't abort???");
84 /// Called before creating the compiler instance
85 fn config(&mut self, _config
: &mut interface
::Config
) {}
86 /// Called after parsing. Return value instructs the compiler whether to
87 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
88 fn after_parsing
<'tcx
>(
90 _compiler
: &interface
::Compiler
,
91 _queries
: &'tcx Queries
<'tcx
>,
95 /// Called after expansion. Return value instructs the compiler whether to
96 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
97 fn after_expansion
<'tcx
>(
99 _compiler
: &interface
::Compiler
,
100 _queries
: &'tcx Queries
<'tcx
>,
102 Compilation
::Continue
104 /// Called after analysis. Return value instructs the compiler whether to
105 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
106 fn after_analysis
<'tcx
>(
108 _compiler
: &interface
::Compiler
,
109 _queries
: &'tcx Queries
<'tcx
>,
111 Compilation
::Continue
116 pub struct TimePassesCallbacks
{
120 impl Callbacks
for TimePassesCallbacks
{
121 fn config(&mut self, config
: &mut interface
::Config
) {
122 // If a --prints=... option has been given, we don't print the "total"
123 // time because it will mess up the --prints output. See #64339.
124 self.time_passes
= config
.opts
.prints
.is_empty()
125 && (config
.opts
.debugging_opts
.time_passes
|| config
.opts
.debugging_opts
.time
);
126 config
.opts
.trimmed_def_paths
= TrimmedDefPaths
::GoodPath
;
130 pub fn diagnostics_registry() -> Registry
{
131 Registry
::new(rustc_error_codes
::DIAGNOSTICS
)
134 /// This is the primary entry point for rustc.
135 pub struct RunCompiler
<'a
, 'b
> {
136 at_args
: &'a
[String
],
137 callbacks
: &'b
mut (dyn Callbacks
+ Send
),
138 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
139 emitter
: Option
<Box
<dyn Write
+ Send
>>,
140 make_codegen_backend
:
141 Option
<Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>>,
144 impl<'a
, 'b
> RunCompiler
<'a
, 'b
> {
145 pub fn new(at_args
: &'a
[String
], callbacks
: &'b
mut (dyn Callbacks
+ Send
)) -> Self {
146 Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
149 /// Set a custom codegen backend.
152 pub fn set_make_codegen_backend(
154 make_codegen_backend
: Option
<
155 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
158 self.make_codegen_backend
= make_codegen_backend
;
162 /// Emit diagnostics to the specified location.
165 pub fn set_emitter(&mut self, emitter
: Option
<Box
<dyn Write
+ Send
>>) -> &mut Self {
166 self.emitter
= emitter
;
170 /// Load files from sources other than the file system.
173 pub fn set_file_loader(
175 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
177 self.file_loader
= file_loader
;
181 /// Parse args and run the compiler.
182 pub fn run(self) -> interface
::Result
<()> {
188 self.make_codegen_backend
,
194 callbacks
: &mut (dyn Callbacks
+ Send
),
195 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
196 emitter
: Option
<Box
<dyn Write
+ Send
>>,
197 make_codegen_backend
: Option
<
198 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
200 ) -> interface
::Result
<()> {
201 let args
= args
::arg_expand_all(at_args
);
203 let diagnostic_output
= emitter
.map_or(DiagnosticOutput
::Default
, DiagnosticOutput
::Raw
);
204 let matches
= match handle_options(&args
) {
205 Some(matches
) => matches
,
206 None
=> return Ok(()),
209 let sopts
= config
::build_session_options(&matches
);
211 if let Some(ref code
) = matches
.opt_str("explain") {
212 handle_explain(diagnostics_registry(), code
, sopts
.error_format
);
216 let cfg
= interface
::parse_cfgspecs(matches
.opt_strs("cfg"));
217 let (odir
, ofile
) = make_output(&matches
);
218 let mut config
= interface
::Config
{
221 input
: Input
::File(PathBuf
::new()),
228 lint_caps
: Default
::default(),
229 parse_sess_created
: None
,
230 register_lints
: None
,
231 override_queries
: None
,
232 make_codegen_backend
,
233 registry
: diagnostics_registry(),
236 match make_input(config
.opts
.error_format
, &matches
.free
) {
237 Err(ErrorReported
) => return Err(ErrorReported
),
238 Ok(Some((input
, input_file_path
))) => {
239 config
.input
= input
;
240 config
.input_path
= input_file_path
;
242 callbacks
.config(&mut config
);
244 Ok(None
) => match matches
.free
.len() {
246 callbacks
.config(&mut config
);
247 interface
::run_compiler(config
, |compiler
| {
248 let sopts
= &compiler
.session().opts
;
249 if sopts
.describe_lints
{
250 let mut lint_store
= rustc_lint
::new_lint_store(
251 sopts
.debugging_opts
.no_interleave_lints
,
252 compiler
.session().unstable_options(),
254 let registered_lints
=
255 if let Some(register_lints
) = compiler
.register_lints() {
256 register_lints(compiler
.session(), &mut lint_store
);
261 describe_lints(compiler
.session(), &lint_store
, registered_lints
);
264 let should_stop
= RustcDefaultCalls
::print_crate_info(
265 &***compiler
.codegen_backend(),
268 compiler
.output_dir(),
269 compiler
.output_file(),
272 if should_stop
== Compilation
::Stop
{
275 early_error(sopts
.error_format
, "no input filename given")
279 1 => panic
!("make_input should have provided valid inputs"),
281 config
.opts
.error_format
,
283 "multiple input filenames provided (first two filenames are `{}` and `{}`)",
284 matches
.free
[0], matches
.free
[1],
290 interface
::run_compiler(config
, |compiler
| {
291 let sess
= compiler
.session();
292 let should_stop
= RustcDefaultCalls
::print_crate_info(
293 &***compiler
.codegen_backend(),
295 Some(compiler
.input()),
296 compiler
.output_dir(),
297 compiler
.output_file(),
300 RustcDefaultCalls
::list_metadata(
302 &*compiler
.codegen_backend().metadata_loader(),
306 .and_then(|| RustcDefaultCalls
::try_process_rlink(sess
, compiler
));
308 if should_stop
== Compilation
::Stop
{
309 return sess
.compile_status();
312 let linker
= compiler
.enter(|queries
| {
313 let early_exit
= || sess
.compile_status().map(|_
| None
);
316 if let Some(ppm
) = &sess
.opts
.pretty
{
317 if ppm
.needs_ast_map() {
318 let expanded_crate
= queries
.expansion()?
.peek().0.clone();
319 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
320 pretty
::print_after_hir_lowering(
325 compiler
.output_file().as_ref().map(|p
| &**p
),
330 let krate
= queries
.parse()?
.take();
331 pretty
::print_after_parsing(
336 compiler
.output_file().as_ref().map(|p
| &**p
),
339 trace
!("finished pretty-printing");
343 if callbacks
.after_parsing(compiler
, queries
) == Compilation
::Stop
{
347 if sess
.opts
.debugging_opts
.parse_only
348 || sess
.opts
.debugging_opts
.show_span
.is_some()
349 || sess
.opts
.debugging_opts
.ast_json_noexpand
355 let (_
, lint_store
) = &*queries
.register_plugins()?
.peek();
357 // Lint plugins are registered; now we can process command line flags.
358 if sess
.opts
.describe_lints
{
359 describe_lints(sess
, lint_store
, true);
364 queries
.expansion()?
;
365 if callbacks
.after_expansion(compiler
, queries
) == Compilation
::Stop
{
369 queries
.prepare_outputs()?
;
371 if sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
)
372 && sess
.opts
.output_types
.len() == 1
377 queries
.global_ctxt()?
;
379 if sess
.opts
.debugging_opts
.no_analysis
|| sess
.opts
.debugging_opts
.ast_json
{
383 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
384 let result
= tcx
.analysis(());
385 if sess
.opts
.debugging_opts
.save_analysis
{
386 let crate_name
= queries
.crate_name()?
.peek().clone();
387 sess
.time("save_analysis", || {
394 compiler
.output_dir().as_ref().map(|p
| &**p
),
403 if callbacks
.after_analysis(compiler
, queries
) == Compilation
::Stop
{
407 queries
.ongoing_codegen()?
;
409 if sess
.opts
.debugging_opts
.print_type_sizes
{
410 sess
.code_stats
.print_type_sizes();
413 let linker
= queries
.linker()?
;
417 if let Some(linker
) = linker
{
418 let _timer
= sess
.timer("link");
422 if sess
.opts
.debugging_opts
.perf_stats
{
423 sess
.print_perf_stats();
426 if sess
.opts
.debugging_opts
.print_fuel
.is_some() {
428 "Fuel used by {}: {}",
429 sess
.opts
.debugging_opts
.print_fuel
.as_ref().unwrap(),
430 sess
.print_fuel
.load(SeqCst
)
439 pub fn set_sigpipe_handler() {
441 // Set the SIGPIPE signal handler, so that an EPIPE
442 // will cause rustc to terminate, as expected.
443 assert_ne
!(libc
::signal(libc
::SIGPIPE
, libc
::SIG_DFL
), libc
::SIG_ERR
);
448 pub fn set_sigpipe_handler() {}
450 // Extract output directory and file from matches.
451 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
452 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
453 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
457 // Extract input (string or file and optional path) from matches.
459 error_format
: ErrorOutputType
,
460 free_matches
: &[String
],
461 ) -> Result
<Option
<(Input
, Option
<PathBuf
>)>, ErrorReported
> {
462 if free_matches
.len() == 1 {
463 let ifile
= &free_matches
[0];
465 let mut src
= String
::new();
466 if io
::stdin().read_to_string(&mut src
).is_err() {
467 // Immediately stop compilation if there was an issue reading
468 // the input (for example if the input stream is not UTF-8).
469 early_error_no_abort(
471 "couldn't read from stdin, as it did not contain valid UTF-8",
473 return Err(ErrorReported
);
475 if let Ok(path
) = env
::var("UNSTABLE_RUSTDOC_TEST_PATH") {
476 let line
= env
::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
477 "when UNSTABLE_RUSTDOC_TEST_PATH is set \
478 UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
480 let line
= isize::from_str_radix(&line
, 10)
481 .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
482 let file_name
= FileName
::doc_test_source_code(PathBuf
::from(path
), line
);
483 Ok(Some((Input
::Str { name: file_name, input: src }
, None
)))
485 Ok(Some((Input
::Str { name: FileName::anon_source_code(&src), input: src }
, None
)))
488 Ok(Some((Input
::File(PathBuf
::from(ifile
)), Some(PathBuf
::from(ifile
)))))
495 /// Whether to stop or continue compilation.
496 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
497 pub enum Compilation
{
503 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
505 Compilation
::Stop
=> Compilation
::Stop
,
506 Compilation
::Continue
=> next(),
511 /// CompilerCalls instance for a regular rustc build.
512 #[derive(Copy, Clone)]
513 pub struct RustcDefaultCalls
;
515 fn stdout_isatty() -> bool
{
516 atty
::is(atty
::Stream
::Stdout
)
519 fn stderr_isatty() -> bool
{
520 atty
::is(atty
::Stream
::Stderr
)
523 fn handle_explain(registry
: Registry
, code
: &str, output
: ErrorOutputType
) {
524 let upper_cased_code
= code
.to_ascii_uppercase();
525 let normalised
= if upper_cased_code
.starts_with('E'
) {
528 format
!("E{0:0>4}", code
)
530 match registry
.try_find_description(&normalised
) {
531 Ok(Some(description
)) => {
532 let mut is_in_code_block
= false;
533 let mut text
= String
::new();
534 // Slice off the leading newline and print.
535 for line
in description
.lines() {
537 line
.find(|c
: char| !c
.is_whitespace()).unwrap_or_else(|| line
.len());
538 let dedented_line
= &line
[indent_level
..];
539 if dedented_line
.starts_with("```") {
540 is_in_code_block
= !is_in_code_block
;
541 text
.push_str(&line
[..(indent_level
+ 3)]);
542 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
550 show_content_with_pager(&text
);
556 early_error(output
, &format
!("no extended information for {}", code
));
558 Err(InvalidErrorCode
) => {
559 early_error(output
, &format
!("{} is not a valid error code", code
));
564 fn show_content_with_pager(content
: &str) {
565 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| {
566 if cfg
!(windows
) { OsString::from("more.com") }
else { OsString::from("less") }
569 let mut fallback_to_println
= false;
571 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
573 if let Some(pipe
) = pager
.stdin
.as_mut() {
574 if pipe
.write_all(content
.as_bytes()).is_err() {
575 fallback_to_println
= true;
579 if pager
.wait().is_err() {
580 fallback_to_println
= true;
584 fallback_to_println
= true;
588 // If pager fails for whatever reason, we should still print the content
589 // to standard output
590 if fallback_to_println
{
591 print
!("{}", content
);
595 impl RustcDefaultCalls
{
596 pub fn try_process_rlink(sess
: &Session
, compiler
: &interface
::Compiler
) -> Compilation
{
597 if sess
.opts
.debugging_opts
.link_only
{
598 if let Input
::File(file
) = compiler
.input() {
599 // FIXME: #![crate_type] and #![crate_name] support not implemented yet
600 sess
.init_crate_types(collect_crate_types(sess
, &[]));
601 let outputs
= compiler
.build_output_filenames(sess
, &[]);
602 let rlink_data
= fs
::read_to_string(file
).unwrap_or_else(|err
| {
603 sess
.fatal(&format
!("failed to read rlink file: {}", err
));
605 let codegen_results
: CodegenResults
=
606 json
::decode(&rlink_data
).unwrap_or_else(|err
| {
607 sess
.fatal(&format
!("failed to decode rlink: {}", err
));
609 let result
= compiler
.codegen_backend().link(sess
, codegen_results
, &outputs
);
610 abort_on_err(result
, sess
);
612 sess
.fatal("rlink must be a file")
616 Compilation
::Continue
620 pub fn list_metadata(
622 metadata_loader
: &dyn MetadataLoader
,
625 if sess
.opts
.debugging_opts
.ls
{
627 Input
::File(ref ifile
) => {
628 let path
= &(*ifile
);
629 let mut v
= Vec
::new();
630 locator
::list_file_metadata(&sess
.target
, path
, metadata_loader
, &mut v
)
632 println
!("{}", String
::from_utf8(v
).unwrap());
634 Input
::Str { .. }
=> {
635 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
638 return Compilation
::Stop
;
641 Compilation
::Continue
645 codegen_backend
: &dyn CodegenBackend
,
647 input
: Option
<&Input
>,
648 odir
: &Option
<PathBuf
>,
649 ofile
: &Option
<PathBuf
>,
651 use rustc_session
::config
::PrintRequest
::*;
652 // PrintRequest::NativeStaticLibs is special - printed during linking
653 // (empty iterator returns true)
654 if sess
.opts
.prints
.iter().all(|&p
| p
== PrintRequest
::NativeStaticLibs
) {
655 return Compilation
::Continue
;
658 let attrs
= match input
{
661 let result
= parse_crate_attrs(sess
, input
);
663 Ok(attrs
) => Some(attrs
),
664 Err(mut parse_error
) => {
666 return Compilation
::Stop
;
671 for req
in &sess
.opts
.prints
{
675 rustc_target
::spec
::TARGETS
.iter().copied().collect
::<Vec
<_
>>();
676 targets
.sort_unstable();
677 println
!("{}", targets
.join("\n"));
679 Sysroot
=> println
!("{}", sess
.sysroot
.display()),
680 TargetLibdir
=> println
!("{}", sess
.target_tlib_path
.dir
.display()),
681 TargetSpec
=> println
!("{}", sess
.target
.to_json().pretty()),
682 FileNames
| CrateName
=> {
683 let input
= input
.unwrap_or_else(|| {
684 early_error(ErrorOutputType
::default(), "no input file provided")
686 let attrs
= attrs
.as_ref().unwrap();
687 let t_outputs
= rustc_interface
::util
::build_output_filenames(
688 input
, odir
, ofile
, attrs
, sess
,
690 let id
= rustc_session
::output
::find_crate_name(sess
, attrs
, input
);
691 if *req
== PrintRequest
::CrateName
{
695 let crate_types
= collect_crate_types(sess
, attrs
);
696 for &style
in &crate_types
{
698 rustc_session
::output
::filename_for_input(sess
, style
, &id
, &t_outputs
);
699 println
!("{}", fname
.file_name().unwrap().to_string_lossy());
707 .filter_map(|&(name
, value
)| {
708 // Note that crt-static is a specially recognized cfg
709 // directive that's printed out here as part of
710 // rust-lang/rust#37406, but in general the
711 // `target_feature` cfg is gated under
712 // rust-lang/rust#29717. For now this is just
713 // specifically allowing the crt-static cfg and that's
714 // it, this is intended to get into Cargo and then go
715 // through to build scripts.
716 if (name
!= sym
::target_feature
|| value
!= Some(sym
::crt_dash_static
))
717 && !sess
.is_nightly_build()
718 && find_gated_cfg(|cfg_sym
| cfg_sym
== name
).is_some()
723 if let Some(value
) = value
{
724 Some(format
!("{}=\"{}\"", name
, value
))
726 Some(name
.to_string())
729 .collect
::<Vec
<String
>>();
736 RelocationModels
| CodeModels
| TlsModels
| TargetCPUs
| TargetFeatures
=> {
737 codegen_backend
.print(*req
, sess
);
739 // Any output here interferes with Cargo's parsing of other printed output
740 PrintRequest
::NativeStaticLibs
=> {}
747 /// Prints version information
748 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
749 let verbose
= matches
.opt_present("verbose");
751 println
!("{} {}", binary
, util
::version_str().unwrap_or("unknown version"));
754 fn unw(x
: Option
<&str>) -> &str {
755 x
.unwrap_or("unknown")
757 println
!("binary: {}", binary
);
758 println
!("commit-hash: {}", unw(util
::commit_hash_str()));
759 println
!("commit-date: {}", unw(util
::commit_date_str()));
760 println
!("host: {}", config
::host_triple());
761 println
!("release: {}", unw(util
::release_str()));
763 let debug_flags
= matches
.opt_strs("Z");
764 let backend_name
= debug_flags
.iter().find_map(|x
| x
.strip_prefix("codegen-backend="));
765 get_codegen_backend(&None
, backend_name
).print_version();
769 fn usage(verbose
: bool
, include_unstable_options
: bool
, nightly_build
: bool
) {
770 let groups
= if verbose { config::rustc_optgroups() }
else { config::rustc_short_optgroups() }
;
771 let mut options
= getopts
::Options
::new();
772 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
773 (option
.apply
)(&mut options
);
775 let message
= "Usage: rustc [OPTIONS] INPUT";
776 let nightly_help
= if nightly_build
{
777 "\n -Z help Print unstable compiler options"
781 let verbose_help
= if verbose
{
784 "\n --help -v Print the full set of options rustc accepts"
786 let at_path
= if verbose
{
787 " @path Read newline separated options from `path`\n"
792 "{options}{at_path}\nAdditional help:
793 -C help Print codegen options
795 Print 'lint' options and default settings{nightly}{verbose}\n",
796 options
= options
.usage(message
),
798 nightly
= nightly_help
,
799 verbose
= verbose_help
803 fn print_wall_help() {
806 The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
807 default. Use `rustc -W help` to see all available lints. It's more common to put
808 warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
809 the command line flag directly.
814 /// Write to stdout lint command options, together with a list of all available lints
815 pub fn describe_lints(sess
: &Session
, lint_store
: &LintStore
, loaded_plugins
: bool
) {
818 Available lint options:
819 -W <foo> Warn about <foo>
823 -F <foo> Forbid <foo> \
824 (deny <foo> and all attempts to override)
829 fn sort_lints(sess
: &Session
, mut lints
: Vec
<&'
static Lint
>) -> Vec
<&'
static Lint
> {
830 // The sort doesn't case-fold but it's doubtful we care.
831 lints
.sort_by_cached_key(|x
: &&Lint
| (x
.default_level(sess
.edition()), x
.name
));
836 lints
: Vec
<(&'
static str, Vec
<LintId
>, bool
)>,
837 ) -> Vec
<(&'
static str, Vec
<LintId
>)> {
838 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
839 lints
.sort_by_key(|l
| l
.0);
843 let (plugin
, builtin
): (Vec
<_
>, _
) =
844 lint_store
.get_lints().iter().cloned().partition(|&lint
| lint
.is_plugin
);
845 let plugin
= sort_lints(sess
, plugin
);
846 let builtin
= sort_lints(sess
, builtin
);
848 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) =
849 lint_store
.get_lint_groups().iter().cloned().partition(|&(.., p
)| p
);
850 let plugin_groups
= sort_lint_groups(plugin_groups
);
851 let builtin_groups
= sort_lint_groups(builtin_groups
);
854 plugin
.iter().chain(&builtin
).map(|&s
| s
.name
.chars().count()).max().unwrap_or(0);
855 let padded
= |x
: &str| {
856 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
861 println
!("Lint checks provided by rustc:\n");
862 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
863 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
865 let print_lints
= |lints
: Vec
<&Lint
>| {
867 let name
= lint
.name_lower().replace("_", "-");
871 lint
.default_level(sess
.edition()).as_str(),
878 print_lints(builtin
);
880 let max_name_len
= max(
884 .chain(&builtin_groups
)
885 .map(|&(s
, _
)| s
.chars().count())
890 let padded
= |x
: &str| {
891 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
896 println
!("Lint groups provided by rustc:\n");
897 println
!(" {} sub-lints", padded("name"));
898 println
!(" {} ---------", padded("----"));
899 println
!(" {} all lints that are set to issue warnings", padded("warnings"));
901 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<LintId
>)>| {
902 for (name
, to
) in lints
{
903 let name
= name
.to_lowercase().replace("_", "-");
906 .map(|x
| x
.to_string().replace("_", "-"))
907 .collect
::<Vec
<String
>>()
909 println
!(" {} {}", padded(&name
), desc
);
914 print_lint_groups(builtin_groups
);
916 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
917 (false, 0, _
) | (false, _
, 0) => {
918 println
!("Lint tools like Clippy can provide additional lints and lint groups.");
920 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
921 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
924 println
!("Lint checks provided by plugins loaded by this crate:\n");
928 println
!("Lint groups provided by plugins loaded by this crate:\n");
929 print_lint_groups(plugin_groups
);
935 fn describe_debug_flags() {
936 println
!("\nAvailable options:\n");
937 print_flag_list("-Z", config
::DB_OPTIONS
);
940 fn describe_codegen_flags() {
941 println
!("\nAvailable codegen options:\n");
942 print_flag_list("-C", config
::CG_OPTIONS
);
945 fn print_flag_list
<T
>(
947 flag_list
: &[(&'
static str, T
, &'
static str, &'
static str)],
949 let max_len
= flag_list
.iter().map(|&(name
, _
, _
, _
)| name
.chars().count()).max().unwrap_or(0);
951 for &(name
, _
, _
, desc
) in flag_list
{
953 " {} {:>width$}=val -- {}",
955 name
.replace("_", "-"),
962 /// Process command line options. Emits messages as appropriate. If compilation
963 /// should continue, returns a getopts::Matches object parsed from args,
964 /// otherwise returns `None`.
966 /// The compiler's handling of options is a little complicated as it ties into
967 /// our stability story. The current intention of each compiler option is to
968 /// have one of two modes:
970 /// 1. An option is stable and can be used everywhere.
971 /// 2. An option is unstable, and can only be used on nightly.
973 /// Like unstable library and language features, however, unstable options have
974 /// always required a form of "opt in" to indicate that you're using them. This
975 /// provides the easy ability to scan a code base to check to see if anything
976 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
978 /// All options behind `-Z` are considered unstable by default. Other top-level
979 /// options can also be considered unstable, and they were unlocked through the
980 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
981 /// instability in both cases, though.
983 /// So with all that in mind, the comments below have some more detail about the
984 /// contortions done here to get things to work out correctly.
985 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
986 // Throw away the first argument, the name of the binary
987 let args
= &args
[1..];
990 // user did not write `-v` nor `-Z unstable-options`, so do not
991 // include that extra information.
993 rustc_feature
::UnstableFeatures
::from_environment(None
).is_nightly_build();
994 usage(false, false, nightly_build
);
998 // Parse with *all* options defined in the compiler, we don't worry about
999 // option stability here we just want to parse as much as possible.
1000 let mut options
= getopts
::Options
::new();
1001 for option
in config
::rustc_optgroups() {
1002 (option
.apply
)(&mut options
);
1004 let matches
= options
.parse(args
).unwrap_or_else(|e
| {
1006 getopts
::Fail
::UnrecognizedOption(ref opt
) => CG_OPTIONS
1008 .map(|&(name
, ..)| ('C'
, name
))
1009 .chain(DB_OPTIONS
.iter().map(|&(name
, ..)| ('Z'
, name
)))
1010 .find(|&(_
, name
)| *opt
== name
.replace("_", "-"))
1011 .map(|(flag
, _
)| format
!("{}. Did you mean `-{} {}`?", e
, flag
, opt
)),
1014 early_error(ErrorOutputType
::default(), &msg
.unwrap_or_else(|| e
.to_string()));
1017 // For all options we just parsed, we check a few aspects:
1019 // * If the option is stable, we're all good
1020 // * If the option wasn't passed, we're all good
1021 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1022 // ourselves), then we require the `-Z unstable-options` flag to unlock
1023 // this option that was passed.
1024 // * If we're a nightly compiler, then unstable options are now unlocked, so
1025 // we're good to go.
1026 // * Otherwise, if we're an unstable option then we generate an error
1027 // (unstable option being used on stable)
1028 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1030 if matches
.opt_present("h") || matches
.opt_present("help") {
1031 // Only show unstable options in --help if we accept unstable options.
1032 let unstable_enabled
= nightly_options
::is_unstable_enabled(&matches
);
1033 let nightly_build
= nightly_options
::match_is_nightly_build(&matches
);
1034 usage(matches
.opt_present("verbose"), unstable_enabled
, nightly_build
);
1038 // Handle the special case of -Wall.
1039 let wall
= matches
.opt_strs("W");
1040 if wall
.iter().any(|x
| *x
== "all") {
1045 // Don't handle -W help here, because we might first load plugins.
1046 let debug_flags
= matches
.opt_strs("Z");
1047 if debug_flags
.iter().any(|x
| *x
== "help") {
1048 describe_debug_flags();
1052 let cg_flags
= matches
.opt_strs("C");
1054 if cg_flags
.iter().any(|x
| *x
== "help") {
1055 describe_codegen_flags();
1059 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1061 ErrorOutputType
::default(),
1062 "the --no-stack-check flag is deprecated and does nothing",
1066 if cg_flags
.iter().any(|x
| *x
== "passes=list") {
1067 let backend_name
= debug_flags
.iter().find_map(|x
| {
1068 if x
.starts_with("codegen-backend=") {
1069 Some(&x
["codegen-backends=".len()..])
1074 get_codegen_backend(&None
, backend_name
).print_passes();
1078 if matches
.opt_present("version") {
1079 version("rustc", &matches
);
1086 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1088 Input
::File(ifile
) => rustc_parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
),
1089 Input
::Str { name, input }
=> rustc_parse
::parse_crate_attrs_from_source_str(
1097 /// Gets a list of extra command-line flags provided by the user, as strings.
1099 /// This function is used during ICEs to show more information useful for
1100 /// debugging, since some ICEs only happens with non-default compiler flags
1101 /// (and the users don't always report them).
1102 fn extra_compiler_flags() -> Option
<(Vec
<String
>, bool
)> {
1103 let args
= env
::args_os().map(|arg
| arg
.to_string_lossy().to_string()).collect
::<Vec
<_
>>();
1105 // Avoid printing help because of empty args. This can suggest the compiler
1106 // itself is not the program root (consider RLS).
1111 let matches
= handle_options(&args
)?
;
1112 let mut result
= Vec
::new();
1113 let mut excluded_cargo_defaults
= false;
1114 for flag
in ICE_REPORT_COMPILER_FLAGS
{
1115 let prefix
= if flag
.len() == 1 { "-" }
else { "--" }
;
1117 for content
in &matches
.opt_strs(flag
) {
1118 // Split always returns the first element
1119 let name
= if let Some(first
) = content
.split('
='
).next() { first }
else { &content }
;
1122 if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
.contains(&name
) { name }
else { content }
;
1124 if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE
.contains(&name
) {
1125 result
.push(format
!("{}{} {}", prefix
, flag
, content
));
1127 excluded_cargo_defaults
= true;
1132 if !result
.is_empty() { Some((result, excluded_cargo_defaults)) }
else { None }
1135 /// Runs a closure and catches unwinds triggered by fatal errors.
1137 /// The compiler currently unwinds with a special sentinel value to abort
1138 /// compilation on fatal errors. This function catches that sentinel and turns
1139 /// the panic into a `Result` instead.
1140 pub fn catch_fatal_errors
<F
: FnOnce() -> R
, R
>(f
: F
) -> Result
<R
, ErrorReported
> {
1141 catch_unwind(panic
::AssertUnwindSafe(f
)).map_err(|value
| {
1142 if value
.is
::<rustc_errors
::FatalErrorMarker
>() {
1145 panic
::resume_unwind(value
);
1150 /// Variant of `catch_fatal_errors` for the `interface::Result` return type
1151 /// that also computes the exit code.
1152 pub fn catch_with_exit_code(f
: impl FnOnce() -> interface
::Result
<()>) -> i32 {
1153 let result
= catch_fatal_errors(f
).and_then(|result
| result
);
1155 Ok(()) => EXIT_SUCCESS
,
1156 Err(_
) => EXIT_FAILURE
,
1160 static DEFAULT_HOOK
: SyncLazy
<Box
<dyn Fn(&panic
::PanicInfo
<'_
>) + Sync
+ Send
+ '
static>> =
1162 let hook
= panic
::take_hook();
1163 panic
::set_hook(Box
::new(|info
| {
1164 // Invoke the default handler, which prints the actual panic message and optionally a backtrace
1165 (*DEFAULT_HOOK
)(info
);
1167 // Separate the output with an empty line
1170 // Print the ICE message
1171 report_ice(info
, BUG_REPORT_URL
);
1176 /// Prints the ICE message, including query stack, but without backtrace.
1178 /// The message will point the user at `bug_report_url` to report the ICE.
1180 /// When `install_ice_hook` is called, this function will be called as the panic
1182 pub fn report_ice(info
: &panic
::PanicInfo
<'_
>, bug_report_url
: &str) {
1183 let emitter
= Box
::new(rustc_errors
::emitter
::EmitterWriter
::stderr(
1184 rustc_errors
::ColorConfig
::Auto
,
1191 let handler
= rustc_errors
::Handler
::with_emitter(true, None
, emitter
);
1193 // a .span_bug or .bug call has already printed what
1194 // it wants to print.
1195 if !info
.payload().is
::<rustc_errors
::ExplicitBug
>() {
1196 let d
= rustc_errors
::Diagnostic
::new(rustc_errors
::Level
::Bug
, "unexpected panic");
1197 handler
.emit_diagnostic(&d
);
1200 let mut xs
: Vec
<Cow
<'
static, str>> = vec
![
1201 "the compiler unexpectedly panicked. this is a bug.".into(),
1202 format
!("we would appreciate a bug report: {}", bug_report_url
).into(),
1204 "rustc {} running on {}",
1205 util
::version_str().unwrap_or("unknown_version"),
1206 config
::host_triple()
1211 if let Some((flags
, excluded_cargo_defaults
)) = extra_compiler_flags() {
1212 xs
.push(format
!("compiler flags: {}", flags
.join(" ")).into());
1214 if excluded_cargo_defaults
{
1215 xs
.push("some of the compiler flags provided by cargo are hidden".into());
1220 handler
.note_without_error(note
);
1223 // If backtraces are enabled, also print the query stack
1224 let backtrace
= env
::var_os("RUST_BACKTRACE").map_or(false, |x
| &x
!= "0");
1226 let num_frames
= if backtrace { None }
else { Some(2) }
;
1228 interface
::try_print_query_stack(&handler
, num_frames
);
1232 if env
::var("RUSTC_BREAK_ON_ICE").is_ok() {
1233 // Trigger a debugger if we crashed during bootstrap
1234 winapi
::um
::debugapi
::DebugBreak();
1239 /// Installs a panic hook that will print the ICE message on unexpected panics.
1241 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
1242 pub fn install_ice_hook() {
1243 SyncLazy
::force(&DEFAULT_HOOK
);
1246 /// This allows tools to enable rust logging without having to magically match rustc's
1247 /// tracing crate version.
1248 pub fn init_rustc_env_logger() {
1249 init_env_logger("RUSTC_LOG")
1252 /// This allows tools to enable rust logging without having to magically match rustc's
1253 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
1254 /// other than `RUSTC_LOG`.
1255 pub fn init_env_logger(env
: &str) {
1256 use tracing_subscriber
::{
1257 filter
::{self, EnvFilter, LevelFilter}
,
1258 layer
::SubscriberExt
,
1261 let filter
= match std
::env
::var(env
) {
1262 Ok(env
) => EnvFilter
::new(env
),
1263 _
=> EnvFilter
::default().add_directive(filter
::Directive
::from(LevelFilter
::WARN
)),
1266 let color_logs
= match std
::env
::var(String
::from(env
) + "_COLOR") {
1267 Ok(value
) => match value
.as_ref() {
1270 "auto" => stderr_isatty(),
1272 ErrorOutputType
::default(),
1274 "invalid log color value '{}': expected one of always, never, or auto",
1279 Err(std
::env
::VarError
::NotPresent
) => stderr_isatty(),
1280 Err(std
::env
::VarError
::NotUnicode(_value
)) => early_error(
1281 ErrorOutputType
::default(),
1282 "non-Unicode log color value: expected one of always, never, or auto",
1286 let layer
= tracing_tree
::HierarchicalLayer
::default()
1287 .with_writer(io
::stderr
)
1288 .with_indent_lines(true)
1289 .with_ansi(color_logs
)
1291 .with_indent_amount(2);
1292 #[cfg(parallel_compiler)]
1293 let layer
= layer
.with_thread_ids(true).with_thread_names(true);
1295 let subscriber
= tracing_subscriber
::Registry
::default().with(filter
).with(layer
);
1296 tracing
::subscriber
::set_global_default(subscriber
).unwrap();
1299 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
1300 mod signal_handler
{
1302 fn backtrace_symbols_fd(
1303 buffer
: *const *mut libc
::c_void
,
1309 extern "C" fn print_stack_trace(_
: libc
::c_int
) {
1310 const MAX_FRAMES
: usize = 256;
1311 static mut STACK_TRACE
: [*mut libc
::c_void
; MAX_FRAMES
] =
1312 [std
::ptr
::null_mut(); MAX_FRAMES
];
1314 let depth
= libc
::backtrace(STACK_TRACE
.as_mut_ptr(), MAX_FRAMES
as i32);
1318 backtrace_symbols_fd(STACK_TRACE
.as_ptr(), depth
, 2);
1322 // When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
1323 // process, print a stack trace and then exit.
1324 pub(super) fn install() {
1326 const ALT_STACK_SIZE
: usize = libc
::MINSIGSTKSZ
+ 64 * 1024;
1327 let mut alt_stack
: libc
::stack_t
= std
::mem
::zeroed();
1329 std
::alloc
::alloc(std
::alloc
::Layout
::from_size_align(ALT_STACK_SIZE
, 1).unwrap())
1330 as *mut libc
::c_void
;
1331 alt_stack
.ss_size
= ALT_STACK_SIZE
;
1332 libc
::sigaltstack(&alt_stack
, std
::ptr
::null_mut());
1334 let mut sa
: libc
::sigaction
= std
::mem
::zeroed();
1335 sa
.sa_sigaction
= print_stack_trace
as libc
::sighandler_t
;
1336 sa
.sa_flags
= libc
::SA_NODEFER
| libc
::SA_RESETHAND
| libc
::SA_ONSTACK
;
1337 libc
::sigemptyset(&mut sa
.sa_mask
);
1338 libc
::sigaction(libc
::SIGSEGV
, &sa
, std
::ptr
::null_mut());
1343 #[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
1344 mod signal_handler
{
1345 pub(super) fn install() {}
1348 pub fn main() -> ! {
1349 let start_time
= Instant
::now();
1350 let start_rss
= get_resident_set_size();
1351 init_rustc_env_logger();
1352 signal_handler
::install();
1353 let mut callbacks
= TimePassesCallbacks
::default();
1355 let exit_code
= catch_with_exit_code(|| {
1356 let args
= env
::args_os()
1359 arg
.into_string().unwrap_or_else(|arg
| {
1361 ErrorOutputType
::default(),
1362 &format
!("argument {} is not valid Unicode: {:?}", i
, arg
),
1366 .collect
::<Vec
<_
>>();
1367 RunCompiler
::new(&args
, &mut callbacks
).run()
1370 if callbacks
.time_passes
{
1371 let end_rss
= get_resident_set_size();
1372 print_time_passes_entry("total", start_time
.elapsed(), start_rss
, end_rss
);
1375 process
::exit(exit_code
)