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"]
11 #![allow(rustc::potential_query_instability)]
16 pub extern crate rustc_plugin_impl
as plugin
;
19 use rustc_codegen_ssa
::{traits::CodegenBackend, CodegenResults}
;
20 use rustc_data_structures
::profiling
::{get_resident_set_size, print_time_passes_entry}
;
21 use rustc_data_structures
::sync
::SeqCst
;
22 use rustc_errors
::registry
::{InvalidErrorCode, Registry}
;
23 use rustc_errors
::{ErrorGuaranteed, PResult}
;
24 use rustc_feature
::find_gated_cfg
;
25 use rustc_interface
::util
::{self, collect_crate_types, get_codegen_backend}
;
26 use rustc_interface
::{interface, Queries}
;
27 use rustc_lint
::LintStore
;
28 use rustc_log
::stdout_isatty
;
29 use rustc_metadata
::locator
;
30 use rustc_save_analysis
as save
;
31 use rustc_save_analysis
::DumpHandler
;
32 use rustc_session
::config
::{nightly_options, CG_OPTIONS, DB_OPTIONS}
;
33 use rustc_session
::config
::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}
;
34 use rustc_session
::cstore
::MetadataLoader
;
35 use rustc_session
::getopts
;
36 use rustc_session
::lint
::{Lint, LintId}
;
37 use rustc_session
::{config, DiagnosticOutput, Session}
;
38 use rustc_session
::{early_error, early_error_no_abort, early_warn}
;
39 use rustc_span
::source_map
::{FileLoader, FileName}
;
40 use rustc_span
::symbol
::sym
;
41 use rustc_target
::json
::ToJson
;
45 use std
::default::Default
;
47 use std
::ffi
::OsString
;
49 use std
::io
::{self, Read, Write}
;
50 use std
::panic
::{self, catch_unwind}
;
51 use std
::path
::PathBuf
;
52 use std
::process
::{self, Command, Stdio}
;
54 use std
::sync
::LazyLock
;
55 use std
::time
::Instant
;
60 /// Exit status code used for successful compilation and help output.
61 pub const EXIT_SUCCESS
: i32 = 0;
63 /// Exit status code used for compilation failures and invalid flags.
64 pub const EXIT_FAILURE
: i32 = 1;
66 const BUG_REPORT_URL
: &str = "https://github.com/rust-lang/rust/issues/new\
67 ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
69 const ICE_REPORT_COMPILER_FLAGS
: &[&str] = &["-Z", "-C", "--crate-type"];
71 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE
: &[&str] = &["metadata", "extra-filename"];
73 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
: &[&str] = &["incremental"];
75 pub fn abort_on_err
<T
>(result
: Result
<T
, ErrorGuaranteed
>, sess
: &Session
) -> T
{
78 sess
.abort_if_errors();
79 panic
!("error reported but abort_if_errors didn't abort???");
86 /// Called before creating the compiler instance
87 fn config(&mut self, _config
: &mut interface
::Config
) {}
88 /// Called after parsing. Return value instructs the compiler whether to
89 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
90 fn after_parsing
<'tcx
>(
92 _compiler
: &interface
::Compiler
,
93 _queries
: &'tcx Queries
<'tcx
>,
97 /// Called after expansion. Return value instructs the compiler whether to
98 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
99 fn after_expansion
<'tcx
>(
101 _compiler
: &interface
::Compiler
,
102 _queries
: &'tcx Queries
<'tcx
>,
104 Compilation
::Continue
106 /// Called after analysis. Return value instructs the compiler whether to
107 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
108 fn after_analysis
<'tcx
>(
110 _compiler
: &interface
::Compiler
,
111 _queries
: &'tcx Queries
<'tcx
>,
113 Compilation
::Continue
118 pub struct TimePassesCallbacks
{
122 impl Callbacks
for TimePassesCallbacks
{
123 fn config(&mut self, config
: &mut interface
::Config
) {
124 // If a --prints=... option has been given, we don't print the "total"
125 // time because it will mess up the --prints output. See #64339.
126 self.time_passes
= config
.opts
.prints
.is_empty()
127 && (config
.opts
.debugging_opts
.time_passes
|| config
.opts
.debugging_opts
.time
);
128 config
.opts
.trimmed_def_paths
= TrimmedDefPaths
::GoodPath
;
132 pub fn diagnostics_registry() -> Registry
{
133 Registry
::new(rustc_error_codes
::DIAGNOSTICS
)
136 /// This is the primary entry point for rustc.
137 pub struct RunCompiler
<'a
, 'b
> {
138 at_args
: &'a
[String
],
139 callbacks
: &'b
mut (dyn Callbacks
+ Send
),
140 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
141 emitter
: Option
<Box
<dyn Write
+ Send
>>,
142 make_codegen_backend
:
143 Option
<Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>>,
146 impl<'a
, 'b
> RunCompiler
<'a
, 'b
> {
147 pub fn new(at_args
: &'a
[String
], callbacks
: &'b
mut (dyn Callbacks
+ Send
)) -> Self {
148 Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
151 /// Set a custom codegen backend.
154 pub fn set_make_codegen_backend(
156 make_codegen_backend
: Option
<
157 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
160 self.make_codegen_backend
= make_codegen_backend
;
164 /// Emit diagnostics to the specified location.
167 pub fn set_emitter(&mut self, emitter
: Option
<Box
<dyn Write
+ Send
>>) -> &mut Self {
168 self.emitter
= emitter
;
172 /// Load files from sources other than the file system.
175 pub fn set_file_loader(
177 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
179 self.file_loader
= file_loader
;
183 /// Parse args and run the compiler.
184 pub fn run(self) -> interface
::Result
<()> {
190 self.make_codegen_backend
,
196 callbacks
: &mut (dyn Callbacks
+ Send
),
197 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
198 emitter
: Option
<Box
<dyn Write
+ Send
>>,
199 make_codegen_backend
: Option
<
200 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
202 ) -> interface
::Result
<()> {
203 let args
= args
::arg_expand_all(at_args
);
205 let diagnostic_output
= emitter
.map_or(DiagnosticOutput
::Default
, DiagnosticOutput
::Raw
);
206 let Some(matches
) = handle_options(&args
) else { return Ok(()) }
;
208 let sopts
= config
::build_session_options(&matches
);
210 if let Some(ref code
) = matches
.opt_str("explain") {
211 handle_explain(diagnostics_registry(), code
, sopts
.error_format
);
215 let cfg
= interface
::parse_cfgspecs(matches
.opt_strs("cfg"));
216 let check_cfg
= interface
::parse_check_cfg(matches
.opt_strs("check-cfg"));
217 let (odir
, ofile
) = make_output(&matches
);
218 let mut config
= interface
::Config
{
221 crate_check_cfg
: check_cfg
,
222 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(reported
) => return Err(reported
),
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
= print_crate_info(
265 &***compiler
.codegen_backend(),
268 compiler
.output_dir(),
269 compiler
.output_file(),
270 compiler
.temps_dir(),
273 if should_stop
== Compilation
::Stop
{
276 early_error(sopts
.error_format
, "no input filename given")
280 1 => panic
!("make_input should have provided valid inputs"),
282 config
.opts
.error_format
,
284 "multiple input filenames provided (first two filenames are `{}` and `{}`)",
285 matches
.free
[0], matches
.free
[1],
291 interface
::run_compiler(config
, |compiler
| {
292 let sess
= compiler
.session();
293 let should_stop
= print_crate_info(
294 &***compiler
.codegen_backend(),
296 Some(compiler
.input()),
297 compiler
.output_dir(),
298 compiler
.output_file(),
299 compiler
.temps_dir(),
302 list_metadata(sess
, &*compiler
.codegen_backend().metadata_loader(), compiler
.input())
304 .and_then(|| try_process_rlink(sess
, compiler
));
306 if should_stop
== Compilation
::Stop
{
307 return sess
.compile_status();
310 let linker
= compiler
.enter(|queries
| {
311 let early_exit
= || sess
.compile_status().map(|_
| None
);
314 if let Some(ppm
) = &sess
.opts
.pretty
{
315 if ppm
.needs_ast_map() {
316 let expanded_crate
= queries
.expansion()?
.peek().0.clone();
317 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
318 pretty
::print_after_hir_lowering(
323 compiler
.output_file().as_ref().map(|p
| &**p
),
328 let krate
= queries
.parse()?
.take();
329 pretty
::print_after_parsing(
334 compiler
.output_file().as_ref().map(|p
| &**p
),
337 trace
!("finished pretty-printing");
341 if callbacks
.after_parsing(compiler
, queries
) == Compilation
::Stop
{
345 if sess
.opts
.debugging_opts
.parse_only
|| sess
.opts
.debugging_opts
.show_span
.is_some() {
350 let (_
, lint_store
) = &*queries
.register_plugins()?
.peek();
352 // Lint plugins are registered; now we can process command line flags.
353 if sess
.opts
.describe_lints
{
354 describe_lints(sess
, lint_store
, true);
359 queries
.expansion()?
;
360 if callbacks
.after_expansion(compiler
, queries
) == Compilation
::Stop
{
364 queries
.prepare_outputs()?
;
366 if sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
)
367 && sess
.opts
.output_types
.len() == 1
372 queries
.global_ctxt()?
;
374 if sess
.opts
.debugging_opts
.no_analysis
{
378 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
379 let result
= tcx
.analysis(());
380 if sess
.opts
.debugging_opts
.save_analysis
{
381 let crate_name
= queries
.crate_name()?
.peek().clone();
382 sess
.time("save_analysis", || {
389 compiler
.output_dir().as_ref().map(|p
| &**p
),
398 if callbacks
.after_analysis(compiler
, queries
) == Compilation
::Stop
{
402 queries
.ongoing_codegen()?
;
404 if sess
.opts
.debugging_opts
.print_type_sizes
{
405 sess
.code_stats
.print_type_sizes();
408 let linker
= queries
.linker()?
;
412 if let Some(linker
) = linker
{
413 let _timer
= sess
.timer("link");
417 if sess
.opts
.debugging_opts
.perf_stats
{
418 sess
.print_perf_stats();
421 if sess
.opts
.debugging_opts
.print_fuel
.is_some() {
423 "Fuel used by {}: {}",
424 sess
.opts
.debugging_opts
.print_fuel
.as_ref().unwrap(),
425 sess
.print_fuel
.load(SeqCst
)
434 pub fn set_sigpipe_handler() {
436 // Set the SIGPIPE signal handler, so that an EPIPE
437 // will cause rustc to terminate, as expected.
438 assert_ne
!(libc
::signal(libc
::SIGPIPE
, libc
::SIG_DFL
), libc
::SIG_ERR
);
443 pub fn set_sigpipe_handler() {}
445 // Extract output directory and file from matches.
446 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
447 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
448 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
452 // Extract input (string or file and optional path) from matches.
454 error_format
: ErrorOutputType
,
455 free_matches
: &[String
],
456 ) -> Result
<Option
<(Input
, Option
<PathBuf
>)>, ErrorGuaranteed
> {
457 if free_matches
.len() == 1 {
458 let ifile
= &free_matches
[0];
460 let mut src
= String
::new();
461 if io
::stdin().read_to_string(&mut src
).is_err() {
462 // Immediately stop compilation if there was an issue reading
463 // the input (for example if the input stream is not UTF-8).
464 let reported
= early_error_no_abort(
466 "couldn't read from stdin, as it did not contain valid UTF-8",
468 return Err(reported
);
470 if let Ok(path
) = env
::var("UNSTABLE_RUSTDOC_TEST_PATH") {
471 let line
= env
::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
472 "when UNSTABLE_RUSTDOC_TEST_PATH is set \
473 UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
475 let line
= isize::from_str_radix(&line
, 10)
476 .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
477 let file_name
= FileName
::doc_test_source_code(PathBuf
::from(path
), line
);
478 Ok(Some((Input
::Str { name: file_name, input: src }
, None
)))
480 Ok(Some((Input
::Str { name: FileName::anon_source_code(&src), input: src }
, None
)))
483 Ok(Some((Input
::File(PathBuf
::from(ifile
)), Some(PathBuf
::from(ifile
)))))
490 /// Whether to stop or continue compilation.
491 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
492 pub enum Compilation
{
498 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
500 Compilation
::Stop
=> Compilation
::Stop
,
501 Compilation
::Continue
=> next(),
506 fn handle_explain(registry
: Registry
, code
: &str, output
: ErrorOutputType
) {
507 let upper_cased_code
= code
.to_ascii_uppercase();
508 let normalised
= if upper_cased_code
.starts_with('E'
) {
511 format
!("E{0:0>4}", code
)
513 match registry
.try_find_description(&normalised
) {
514 Ok(Some(description
)) => {
515 let mut is_in_code_block
= false;
516 let mut text
= String
::new();
517 // Slice off the leading newline and print.
518 for line
in description
.lines() {
520 line
.find(|c
: char| !c
.is_whitespace()).unwrap_or_else(|| line
.len());
521 let dedented_line
= &line
[indent_level
..];
522 if dedented_line
.starts_with("```") {
523 is_in_code_block
= !is_in_code_block
;
524 text
.push_str(&line
[..(indent_level
+ 3)]);
525 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
533 show_content_with_pager(&text
);
539 early_error(output
, &format
!("no extended information for {}", code
));
541 Err(InvalidErrorCode
) => {
542 early_error(output
, &format
!("{} is not a valid error code", code
));
547 fn show_content_with_pager(content
: &str) {
548 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| {
549 if cfg
!(windows
) { OsString::from("more.com") }
else { OsString::from("less") }
552 let mut fallback_to_println
= false;
554 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
556 if let Some(pipe
) = pager
.stdin
.as_mut() {
557 if pipe
.write_all(content
.as_bytes()).is_err() {
558 fallback_to_println
= true;
562 if pager
.wait().is_err() {
563 fallback_to_println
= true;
567 fallback_to_println
= true;
571 // If pager fails for whatever reason, we should still print the content
572 // to standard output
573 if fallback_to_println
{
574 print
!("{}", content
);
578 pub fn try_process_rlink(sess
: &Session
, compiler
: &interface
::Compiler
) -> Compilation
{
579 if sess
.opts
.debugging_opts
.link_only
{
580 if let Input
::File(file
) = compiler
.input() {
581 // FIXME: #![crate_type] and #![crate_name] support not implemented yet
582 sess
.init_crate_types(collect_crate_types(sess
, &[]));
583 let outputs
= compiler
.build_output_filenames(sess
, &[]);
584 let rlink_data
= fs
::read(file
).unwrap_or_else(|err
| {
585 sess
.fatal(&format
!("failed to read rlink file: {}", err
));
587 let codegen_results
= match CodegenResults
::deserialize_rlink(rlink_data
) {
588 Ok(codegen
) => codegen
,
590 sess
.fatal(&format
!("Could not deserialize .rlink file: {error}"));
593 let result
= compiler
.codegen_backend().link(sess
, codegen_results
, &outputs
);
594 abort_on_err(result
, sess
);
596 sess
.fatal("rlink must be a file")
600 Compilation
::Continue
604 pub fn list_metadata(
606 metadata_loader
: &dyn MetadataLoader
,
609 if sess
.opts
.debugging_opts
.ls
{
611 Input
::File(ref ifile
) => {
612 let path
= &(*ifile
);
613 let mut v
= Vec
::new();
614 locator
::list_file_metadata(&sess
.target
, path
, metadata_loader
, &mut v
).unwrap();
615 println
!("{}", String
::from_utf8(v
).unwrap());
617 Input
::Str { .. }
=> {
618 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
621 return Compilation
::Stop
;
624 Compilation
::Continue
628 codegen_backend
: &dyn CodegenBackend
,
630 input
: Option
<&Input
>,
631 odir
: &Option
<PathBuf
>,
632 ofile
: &Option
<PathBuf
>,
633 temps_dir
: &Option
<PathBuf
>,
635 use rustc_session
::config
::PrintRequest
::*;
636 // NativeStaticLibs and LinkArgs are special - printed during linking
637 // (empty iterator returns true)
638 if sess
.opts
.prints
.iter().all(|&p
| p
== NativeStaticLibs
|| p
== LinkArgs
) {
639 return Compilation
::Continue
;
642 let attrs
= match input
{
645 let result
= parse_crate_attrs(sess
, input
);
647 Ok(attrs
) => Some(attrs
),
648 Err(mut parse_error
) => {
650 return Compilation
::Stop
;
655 for req
in &sess
.opts
.prints
{
658 let mut targets
= rustc_target
::spec
::TARGETS
.iter().copied().collect
::<Vec
<_
>>();
659 targets
.sort_unstable();
660 println
!("{}", targets
.join("\n"));
662 Sysroot
=> println
!("{}", sess
.sysroot
.display()),
663 TargetLibdir
=> println
!("{}", sess
.target_tlib_path
.dir
.display()),
665 println
!("{}", serde_json
::to_string_pretty(&sess
.target
.to_json()).unwrap());
667 FileNames
| CrateName
=> {
668 let input
= input
.unwrap_or_else(|| {
669 early_error(ErrorOutputType
::default(), "no input file provided")
671 let attrs
= attrs
.as_ref().unwrap();
672 let t_outputs
= rustc_interface
::util
::build_output_filenames(
673 input
, odir
, ofile
, temps_dir
, attrs
, sess
,
675 let id
= rustc_session
::output
::find_crate_name(sess
, attrs
, input
);
676 if *req
== PrintRequest
::CrateName
{
680 let crate_types
= collect_crate_types(sess
, attrs
);
681 for &style
in &crate_types
{
683 rustc_session
::output
::filename_for_input(sess
, style
, &id
, &t_outputs
);
684 println
!("{}", fname
.file_name().unwrap().to_string_lossy());
692 .filter_map(|&(name
, value
)| {
693 // Note that crt-static is a specially recognized cfg
694 // directive that's printed out here as part of
695 // rust-lang/rust#37406, but in general the
696 // `target_feature` cfg is gated under
697 // rust-lang/rust#29717. For now this is just
698 // specifically allowing the crt-static cfg and that's
699 // it, this is intended to get into Cargo and then go
700 // through to build scripts.
701 if (name
!= sym
::target_feature
|| value
!= Some(sym
::crt_dash_static
))
702 && !sess
.is_nightly_build()
703 && find_gated_cfg(|cfg_sym
| cfg_sym
== name
).is_some()
708 if let Some(value
) = value
{
709 Some(format
!("{}=\"{}\"", name
, value
))
711 Some(name
.to_string())
714 .collect
::<Vec
<String
>>();
725 | StackProtectorStrategies
726 | TargetFeatures
=> {
727 codegen_backend
.print(*req
, sess
);
729 // Any output here interferes with Cargo's parsing of other printed output
730 NativeStaticLibs
=> {}
737 /// Prints version information
738 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
739 let verbose
= matches
.opt_present("verbose");
741 println
!("{} {}", binary
, util
::version_str().unwrap_or("unknown version"));
744 fn unw(x
: Option
<&str>) -> &str {
745 x
.unwrap_or("unknown")
747 println
!("binary: {}", binary
);
748 println
!("commit-hash: {}", unw(util
::commit_hash_str()));
749 println
!("commit-date: {}", unw(util
::commit_date_str()));
750 println
!("host: {}", config
::host_triple());
751 println
!("release: {}", unw(util
::release_str()));
753 let debug_flags
= matches
.opt_strs("Z");
754 let backend_name
= debug_flags
.iter().find_map(|x
| x
.strip_prefix("codegen-backend="));
755 get_codegen_backend(&None
, backend_name
).print_version();
759 fn usage(verbose
: bool
, include_unstable_options
: bool
, nightly_build
: bool
) {
760 let groups
= if verbose { config::rustc_optgroups() }
else { config::rustc_short_optgroups() }
;
761 let mut options
= getopts
::Options
::new();
762 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
763 (option
.apply
)(&mut options
);
765 let message
= "Usage: rustc [OPTIONS] INPUT";
766 let nightly_help
= if nightly_build
{
767 "\n -Z help Print unstable compiler options"
771 let verbose_help
= if verbose
{
774 "\n --help -v Print the full set of options rustc accepts"
776 let at_path
= if verbose
{
777 " @path Read newline separated options from `path`\n"
782 "{options}{at_path}\nAdditional help:
783 -C help Print codegen options
785 Print 'lint' options and default settings{nightly}{verbose}\n",
786 options
= options
.usage(message
),
788 nightly
= nightly_help
,
789 verbose
= verbose_help
793 fn print_wall_help() {
796 The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
797 default. Use `rustc -W help` to see all available lints. It's more common to put
798 warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
799 the command line flag directly.
804 /// Write to stdout lint command options, together with a list of all available lints
805 pub fn describe_lints(sess
: &Session
, lint_store
: &LintStore
, loaded_plugins
: bool
) {
808 Available lint options:
809 -W <foo> Warn about <foo>
813 -F <foo> Forbid <foo> \
814 (deny <foo> and all attempts to override)
819 fn sort_lints(sess
: &Session
, mut lints
: Vec
<&'
static Lint
>) -> Vec
<&'
static Lint
> {
820 // The sort doesn't case-fold but it's doubtful we care.
821 lints
.sort_by_cached_key(|x
: &&Lint
| (x
.default_level(sess
.edition()), x
.name
));
826 lints
: Vec
<(&'
static str, Vec
<LintId
>, bool
)>,
827 ) -> Vec
<(&'
static str, Vec
<LintId
>)> {
828 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
829 lints
.sort_by_key(|l
| l
.0);
833 let (plugin
, builtin
): (Vec
<_
>, _
) =
834 lint_store
.get_lints().iter().cloned().partition(|&lint
| lint
.is_plugin
);
835 let plugin
= sort_lints(sess
, plugin
);
836 let builtin
= sort_lints(sess
, builtin
);
838 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) =
839 lint_store
.get_lint_groups().partition(|&(.., p
)| p
);
840 let plugin_groups
= sort_lint_groups(plugin_groups
);
841 let builtin_groups
= sort_lint_groups(builtin_groups
);
844 plugin
.iter().chain(&builtin
).map(|&s
| s
.name
.chars().count()).max().unwrap_or(0);
845 let padded
= |x
: &str| {
846 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
851 println
!("Lint checks provided by rustc:\n");
852 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
853 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
855 let print_lints
= |lints
: Vec
<&Lint
>| {
857 let name
= lint
.name_lower().replace('_'
, "-");
861 lint
.default_level(sess
.edition()).as_str(),
868 print_lints(builtin
);
870 let max_name_len
= max(
874 .chain(&builtin_groups
)
875 .map(|&(s
, _
)| s
.chars().count())
880 let padded
= |x
: &str| {
881 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
886 println
!("Lint groups provided by rustc:\n");
887 println
!(" {} sub-lints", padded("name"));
888 println
!(" {} ---------", padded("----"));
889 println
!(" {} all lints that are set to issue warnings", padded("warnings"));
891 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<LintId
>)>| {
892 for (name
, to
) in lints
{
893 let name
= name
.to_lowercase().replace('_'
, "-");
896 .map(|x
| x
.to_string().replace('_'
, "-"))
897 .collect
::<Vec
<String
>>()
899 println
!(" {} {}", padded(&name
), desc
);
904 print_lint_groups(builtin_groups
);
906 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
907 (false, 0, _
) | (false, _
, 0) => {
908 println
!("Lint tools like Clippy can provide additional lints and lint groups.");
910 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
911 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
914 println
!("Lint checks provided by plugins loaded by this crate:\n");
918 println
!("Lint groups provided by plugins loaded by this crate:\n");
919 print_lint_groups(plugin_groups
);
925 fn describe_debug_flags() {
926 println
!("\nAvailable options:\n");
927 print_flag_list("-Z", config
::DB_OPTIONS
);
930 fn describe_codegen_flags() {
931 println
!("\nAvailable codegen options:\n");
932 print_flag_list("-C", config
::CG_OPTIONS
);
935 fn print_flag_list
<T
>(
937 flag_list
: &[(&'
static str, T
, &'
static str, &'
static str)],
939 let max_len
= flag_list
.iter().map(|&(name
, _
, _
, _
)| name
.chars().count()).max().unwrap_or(0);
941 for &(name
, _
, _
, desc
) in flag_list
{
943 " {} {:>width$}=val -- {}",
945 name
.replace('_'
, "-"),
952 /// Process command line options. Emits messages as appropriate. If compilation
953 /// should continue, returns a getopts::Matches object parsed from args,
954 /// otherwise returns `None`.
956 /// The compiler's handling of options is a little complicated as it ties into
957 /// our stability story. The current intention of each compiler option is to
958 /// have one of two modes:
960 /// 1. An option is stable and can be used everywhere.
961 /// 2. An option is unstable, and can only be used on nightly.
963 /// Like unstable library and language features, however, unstable options have
964 /// always required a form of "opt in" to indicate that you're using them. This
965 /// provides the easy ability to scan a code base to check to see if anything
966 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
968 /// All options behind `-Z` are considered unstable by default. Other top-level
969 /// options can also be considered unstable, and they were unlocked through the
970 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
971 /// instability in both cases, though.
973 /// So with all that in mind, the comments below have some more detail about the
974 /// contortions done here to get things to work out correctly.
975 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
976 // Throw away the first argument, the name of the binary
977 let args
= &args
[1..];
980 // user did not write `-v` nor `-Z unstable-options`, so do not
981 // include that extra information.
983 rustc_feature
::UnstableFeatures
::from_environment(None
).is_nightly_build();
984 usage(false, false, nightly_build
);
988 // Parse with *all* options defined in the compiler, we don't worry about
989 // option stability here we just want to parse as much as possible.
990 let mut options
= getopts
::Options
::new();
991 for option
in config
::rustc_optgroups() {
992 (option
.apply
)(&mut options
);
994 let matches
= options
.parse(args
).unwrap_or_else(|e
| {
996 getopts
::Fail
::UnrecognizedOption(ref opt
) => CG_OPTIONS
998 .map(|&(name
, ..)| ('C'
, name
))
999 .chain(DB_OPTIONS
.iter().map(|&(name
, ..)| ('Z'
, name
)))
1000 .find(|&(_
, name
)| *opt
== name
.replace('_'
, "-"))
1001 .map(|(flag
, _
)| format
!("{}. Did you mean `-{} {}`?", e
, flag
, opt
)),
1004 early_error(ErrorOutputType
::default(), &msg
.unwrap_or_else(|| e
.to_string()));
1007 // For all options we just parsed, we check a few aspects:
1009 // * If the option is stable, we're all good
1010 // * If the option wasn't passed, we're all good
1011 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1012 // ourselves), then we require the `-Z unstable-options` flag to unlock
1013 // this option that was passed.
1014 // * If we're a nightly compiler, then unstable options are now unlocked, so
1015 // we're good to go.
1016 // * Otherwise, if we're an unstable option then we generate an error
1017 // (unstable option being used on stable)
1018 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1020 if matches
.opt_present("h") || matches
.opt_present("help") {
1021 // Only show unstable options in --help if we accept unstable options.
1022 let unstable_enabled
= nightly_options
::is_unstable_enabled(&matches
);
1023 let nightly_build
= nightly_options
::match_is_nightly_build(&matches
);
1024 usage(matches
.opt_present("verbose"), unstable_enabled
, nightly_build
);
1028 // Handle the special case of -Wall.
1029 let wall
= matches
.opt_strs("W");
1030 if wall
.iter().any(|x
| *x
== "all") {
1032 rustc_errors
::FatalError
.raise();
1035 // Don't handle -W help here, because we might first load plugins.
1036 let debug_flags
= matches
.opt_strs("Z");
1037 if debug_flags
.iter().any(|x
| *x
== "help") {
1038 describe_debug_flags();
1042 let cg_flags
= matches
.opt_strs("C");
1044 if cg_flags
.iter().any(|x
| *x
== "help") {
1045 describe_codegen_flags();
1049 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1051 ErrorOutputType
::default(),
1052 "the --no-stack-check flag is deprecated and does nothing",
1056 if cg_flags
.iter().any(|x
| *x
== "passes=list") {
1057 let backend_name
= debug_flags
.iter().find_map(|x
| x
.strip_prefix("codegen-backend="));
1058 get_codegen_backend(&None
, backend_name
).print_passes();
1062 if matches
.opt_present("version") {
1063 version("rustc", &matches
);
1070 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1072 Input
::File(ifile
) => rustc_parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
),
1073 Input
::Str { name, input }
=> rustc_parse
::parse_crate_attrs_from_source_str(
1081 /// Gets a list of extra command-line flags provided by the user, as strings.
1083 /// This function is used during ICEs to show more information useful for
1084 /// debugging, since some ICEs only happens with non-default compiler flags
1085 /// (and the users don't always report them).
1086 fn extra_compiler_flags() -> Option
<(Vec
<String
>, bool
)> {
1087 let mut args
= env
::args_os().map(|arg
| arg
.to_string_lossy().to_string()).peekable();
1089 let mut result
= Vec
::new();
1090 let mut excluded_cargo_defaults
= false;
1091 while let Some(arg
) = args
.next() {
1092 if let Some(a
) = ICE_REPORT_COMPILER_FLAGS
.iter().find(|a
| arg
.starts_with(*a
)) {
1093 let content
= if arg
.len() == a
.len() {
1095 Some(arg
) => arg
.to_string(),
1098 } else if arg
.get(a
.len()..a
.len() + 1) == Some("=") {
1099 arg
[a
.len() + 1..].to_string()
1101 arg
[a
.len()..].to_string()
1103 if ICE_REPORT_COMPILER_FLAGS_EXCLUDE
.iter().any(|exc
| content
.starts_with(exc
)) {
1104 excluded_cargo_defaults
= true;
1106 result
.push(a
.to_string());
1107 match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
.iter().find(|s
| content
.starts_with(*s
))
1109 Some(s
) => result
.push(s
.to_string()),
1110 None
=> result
.push(content
),
1116 if !result
.is_empty() { Some((result, excluded_cargo_defaults)) }
else { None }
1119 /// Runs a closure and catches unwinds triggered by fatal errors.
1121 /// The compiler currently unwinds with a special sentinel value to abort
1122 /// compilation on fatal errors. This function catches that sentinel and turns
1123 /// the panic into a `Result` instead.
1124 pub fn catch_fatal_errors
<F
: FnOnce() -> R
, R
>(f
: F
) -> Result
<R
, ErrorGuaranteed
> {
1125 catch_unwind(panic
::AssertUnwindSafe(f
)).map_err(|value
| {
1126 if value
.is
::<rustc_errors
::FatalErrorMarker
>() {
1127 ErrorGuaranteed
::unchecked_claim_error_was_emitted()
1129 panic
::resume_unwind(value
);
1134 /// Variant of `catch_fatal_errors` for the `interface::Result` return type
1135 /// that also computes the exit code.
1136 pub fn catch_with_exit_code(f
: impl FnOnce() -> interface
::Result
<()>) -> i32 {
1137 let result
= catch_fatal_errors(f
).and_then(|result
| result
);
1139 Ok(()) => EXIT_SUCCESS
,
1140 Err(_
) => EXIT_FAILURE
,
1144 static DEFAULT_HOOK
: LazyLock
<Box
<dyn Fn(&panic
::PanicInfo
<'_
>) + Sync
+ Send
+ '
static>> =
1146 let hook
= panic
::take_hook();
1147 panic
::set_hook(Box
::new(|info
| {
1148 // Invoke the default handler, which prints the actual panic message and optionally a backtrace
1149 (*DEFAULT_HOOK
)(info
);
1151 // Separate the output with an empty line
1154 // Print the ICE message
1155 report_ice(info
, BUG_REPORT_URL
);
1160 /// Prints the ICE message, including query stack, but without backtrace.
1162 /// The message will point the user at `bug_report_url` to report the ICE.
1164 /// When `install_ice_hook` is called, this function will be called as the panic
1166 pub fn report_ice(info
: &panic
::PanicInfo
<'_
>, bug_report_url
: &str) {
1167 let fallback_bundle
=
1168 rustc_errors
::fallback_fluent_bundle(rustc_errors
::DEFAULT_LOCALE_RESOURCES
, false);
1169 let emitter
= Box
::new(rustc_errors
::emitter
::EmitterWriter
::stderr(
1170 rustc_errors
::ColorConfig
::Auto
,
1179 let handler
= rustc_errors
::Handler
::with_emitter(true, None
, emitter
);
1181 // a .span_bug or .bug call has already printed what
1182 // it wants to print.
1183 if !info
.payload().is
::<rustc_errors
::ExplicitBug
>() {
1184 let mut d
= rustc_errors
::Diagnostic
::new(rustc_errors
::Level
::Bug
, "unexpected panic");
1185 handler
.emit_diagnostic(&mut d
);
1188 let mut xs
: Vec
<Cow
<'
static, str>> = vec
![
1189 "the compiler unexpectedly panicked. this is a bug.".into(),
1190 format
!("we would appreciate a bug report: {}", bug_report_url
).into(),
1192 "rustc {} running on {}",
1193 util
::version_str().unwrap_or("unknown_version"),
1194 config
::host_triple()
1199 if let Some((flags
, excluded_cargo_defaults
)) = extra_compiler_flags() {
1200 xs
.push(format
!("compiler flags: {}", flags
.join(" ")).into());
1202 if excluded_cargo_defaults
{
1203 xs
.push("some of the compiler flags provided by cargo are hidden".into());
1208 handler
.note_without_error(note
.as_ref());
1211 // If backtraces are enabled, also print the query stack
1212 let backtrace
= env
::var_os("RUST_BACKTRACE").map_or(false, |x
| &x
!= "0");
1214 let num_frames
= if backtrace { None }
else { Some(2) }
;
1216 interface
::try_print_query_stack(&handler
, num_frames
);
1220 if env
::var("RUSTC_BREAK_ON_ICE").is_ok() {
1221 // Trigger a debugger if we crashed during bootstrap
1222 winapi
::um
::debugapi
::DebugBreak();
1227 /// Installs a panic hook that will print the ICE message on unexpected panics.
1229 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
1230 pub fn install_ice_hook() {
1231 // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
1232 // full backtraces. When a compiler ICE happens, we want to gather
1233 // as much information as possible to present in the issue opened
1234 // by the user. Compiler developers and other rustc users can
1235 // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
1236 // (e.g. `RUST_BACKTRACE=1`)
1237 if std
::env
::var("RUST_BACKTRACE").is_err() {
1238 std
::env
::set_var("RUST_BACKTRACE", "full");
1240 LazyLock
::force(&DEFAULT_HOOK
);
1243 /// This allows tools to enable rust logging without having to magically match rustc's
1244 /// tracing crate version.
1245 pub fn init_rustc_env_logger() {
1246 if let Err(error
) = rustc_log
::init_rustc_env_logger() {
1247 early_error(ErrorOutputType
::default(), &error
.to_string());
1251 /// This allows tools to enable rust logging without having to magically match rustc's
1252 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
1253 /// other than `RUSTC_LOG`.
1254 pub fn init_env_logger(env
: &str) {
1255 if let Err(error
) = rustc_log
::init_env_logger(env
) {
1256 early_error(ErrorOutputType
::default(), &error
.to_string());
1260 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
1261 mod signal_handler
{
1263 fn backtrace_symbols_fd(
1264 buffer
: *const *mut libc
::c_void
,
1270 extern "C" fn print_stack_trace(_
: libc
::c_int
) {
1271 const MAX_FRAMES
: usize = 256;
1272 static mut STACK_TRACE
: [*mut libc
::c_void
; MAX_FRAMES
] =
1273 [std
::ptr
::null_mut(); MAX_FRAMES
];
1275 let depth
= libc
::backtrace(STACK_TRACE
.as_mut_ptr(), MAX_FRAMES
as i32);
1279 backtrace_symbols_fd(STACK_TRACE
.as_ptr(), depth
, 2);
1283 // When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
1284 // process, print a stack trace and then exit.
1285 pub(super) fn install() {
1287 const ALT_STACK_SIZE
: usize = libc
::MINSIGSTKSZ
+ 64 * 1024;
1288 let mut alt_stack
: libc
::stack_t
= std
::mem
::zeroed();
1290 std
::alloc
::alloc(std
::alloc
::Layout
::from_size_align(ALT_STACK_SIZE
, 1).unwrap())
1291 as *mut libc
::c_void
;
1292 alt_stack
.ss_size
= ALT_STACK_SIZE
;
1293 libc
::sigaltstack(&alt_stack
, std
::ptr
::null_mut());
1295 let mut sa
: libc
::sigaction
= std
::mem
::zeroed();
1296 sa
.sa_sigaction
= print_stack_trace
as libc
::sighandler_t
;
1297 sa
.sa_flags
= libc
::SA_NODEFER
| libc
::SA_RESETHAND
| libc
::SA_ONSTACK
;
1298 libc
::sigemptyset(&mut sa
.sa_mask
);
1299 libc
::sigaction(libc
::SIGSEGV
, &sa
, std
::ptr
::null_mut());
1304 #[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
1305 mod signal_handler
{
1306 pub(super) fn install() {}
1309 pub fn main() -> ! {
1310 let start_time
= Instant
::now();
1311 let start_rss
= get_resident_set_size();
1312 init_rustc_env_logger();
1313 signal_handler
::install();
1314 let mut callbacks
= TimePassesCallbacks
::default();
1316 let exit_code
= catch_with_exit_code(|| {
1317 let args
= env
::args_os()
1320 arg
.into_string().unwrap_or_else(|arg
| {
1322 ErrorOutputType
::default(),
1323 &format
!("argument {} is not valid Unicode: {:?}", i
, arg
),
1327 .collect
::<Vec
<_
>>();
1328 RunCompiler
::new(&args
, &mut callbacks
).run()
1331 if callbacks
.time_passes
{
1332 let end_rss
= get_resident_set_size();
1333 print_time_passes_entry("total", start_time
.elapsed(), start_rss
, end_rss
);
1336 process
::exit(exit_code
)