5 //! This API is completely unstable and subject to change.
7 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
10 #![feature(once_cell)]
11 #![recursion_limit = "256"]
12 #![allow(rustc::potential_query_instability)]
17 pub extern crate rustc_plugin_impl
as plugin
;
20 use rustc_codegen_ssa
::{traits::CodegenBackend, CodegenResults}
;
21 use rustc_data_structures
::profiling
::{get_resident_set_size, print_time_passes_entry}
;
22 use rustc_data_structures
::sync
::SeqCst
;
23 use rustc_errors
::registry
::{InvalidErrorCode, Registry}
;
24 use rustc_errors
::{ErrorGuaranteed, PResult}
;
25 use rustc_feature
::find_gated_cfg
;
26 use rustc_interface
::util
::{self, collect_crate_types, get_codegen_backend}
;
27 use rustc_interface
::{interface, Queries}
;
28 use rustc_lint
::LintStore
;
29 use rustc_log
::stdout_isatty
;
30 use rustc_metadata
::locator
;
31 use rustc_save_analysis
as save
;
32 use rustc_save_analysis
::DumpHandler
;
33 use rustc_serialize
::json
::ToJson
;
34 use rustc_session
::config
::{nightly_options, CG_OPTIONS, DB_OPTIONS}
;
35 use rustc_session
::config
::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}
;
36 use rustc_session
::cstore
::MetadataLoader
;
37 use rustc_session
::getopts
;
38 use rustc_session
::lint
::{Lint, LintId}
;
39 use rustc_session
::{config, DiagnosticOutput, Session}
;
40 use rustc_session
::{early_error, early_error_no_abort, early_warn}
;
41 use rustc_span
::source_map
::{FileLoader, FileName}
;
42 use rustc_span
::symbol
::sym
;
46 use std
::default::Default
;
48 use std
::ffi
::OsString
;
50 use std
::io
::{self, Read, Write}
;
51 use std
::lazy
::SyncLazy
;
52 use std
::panic
::{self, catch_unwind}
;
53 use std
::path
::PathBuf
;
54 use std
::process
::{self, Command, Stdio}
;
56 use std
::time
::Instant
;
61 /// Exit status code used for successful compilation and help output.
62 pub const EXIT_SUCCESS
: i32 = 0;
64 /// Exit status code used for compilation failures and invalid flags.
65 pub const EXIT_FAILURE
: i32 = 1;
67 const BUG_REPORT_URL
: &str = "https://github.com/rust-lang/rust/issues/new\
68 ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
70 const ICE_REPORT_COMPILER_FLAGS
: &[&str] = &["-Z", "-C", "--crate-type"];
72 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE
: &[&str] = &["metadata", "extra-filename"];
74 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
: &[&str] = &["incremental"];
76 pub fn abort_on_err
<T
>(result
: Result
<T
, ErrorGuaranteed
>, sess
: &Session
) -> T
{
79 sess
.abort_if_errors();
80 panic
!("error reported but abort_if_errors didn't abort???");
87 /// Called before creating the compiler instance
88 fn config(&mut self, _config
: &mut interface
::Config
) {}
89 /// Called after parsing. Return value instructs the compiler whether to
90 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
91 fn after_parsing
<'tcx
>(
93 _compiler
: &interface
::Compiler
,
94 _queries
: &'tcx Queries
<'tcx
>,
98 /// Called after expansion. Return value instructs the compiler whether to
99 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
100 fn after_expansion
<'tcx
>(
102 _compiler
: &interface
::Compiler
,
103 _queries
: &'tcx Queries
<'tcx
>,
105 Compilation
::Continue
107 /// Called after analysis. Return value instructs the compiler whether to
108 /// continue the compilation afterwards (defaults to `Compilation::Continue`)
109 fn after_analysis
<'tcx
>(
111 _compiler
: &interface
::Compiler
,
112 _queries
: &'tcx Queries
<'tcx
>,
114 Compilation
::Continue
119 pub struct TimePassesCallbacks
{
123 impl Callbacks
for TimePassesCallbacks
{
124 fn config(&mut self, config
: &mut interface
::Config
) {
125 // If a --prints=... option has been given, we don't print the "total"
126 // time because it will mess up the --prints output. See #64339.
127 self.time_passes
= config
.opts
.prints
.is_empty()
128 && (config
.opts
.debugging_opts
.time_passes
|| config
.opts
.debugging_opts
.time
);
129 config
.opts
.trimmed_def_paths
= TrimmedDefPaths
::GoodPath
;
133 pub fn diagnostics_registry() -> Registry
{
134 Registry
::new(rustc_error_codes
::DIAGNOSTICS
)
137 /// This is the primary entry point for rustc.
138 pub struct RunCompiler
<'a
, 'b
> {
139 at_args
: &'a
[String
],
140 callbacks
: &'b
mut (dyn Callbacks
+ Send
),
141 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
142 emitter
: Option
<Box
<dyn Write
+ Send
>>,
143 make_codegen_backend
:
144 Option
<Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>>,
147 impl<'a
, 'b
> RunCompiler
<'a
, 'b
> {
148 pub fn new(at_args
: &'a
[String
], callbacks
: &'b
mut (dyn Callbacks
+ Send
)) -> Self {
149 Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
152 /// Set a custom codegen backend.
155 pub fn set_make_codegen_backend(
157 make_codegen_backend
: Option
<
158 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
161 self.make_codegen_backend
= make_codegen_backend
;
165 /// Emit diagnostics to the specified location.
168 pub fn set_emitter(&mut self, emitter
: Option
<Box
<dyn Write
+ Send
>>) -> &mut Self {
169 self.emitter
= emitter
;
173 /// Load files from sources other than the file system.
176 pub fn set_file_loader(
178 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
180 self.file_loader
= file_loader
;
184 /// Parse args and run the compiler.
185 pub fn run(self) -> interface
::Result
<()> {
191 self.make_codegen_backend
,
197 callbacks
: &mut (dyn Callbacks
+ Send
),
198 file_loader
: Option
<Box
<dyn FileLoader
+ Send
+ Sync
>>,
199 emitter
: Option
<Box
<dyn Write
+ Send
>>,
200 make_codegen_backend
: Option
<
201 Box
<dyn FnOnce(&config
::Options
) -> Box
<dyn CodegenBackend
> + Send
>,
203 ) -> interface
::Result
<()> {
204 let args
= args
::arg_expand_all(at_args
);
206 let diagnostic_output
= emitter
.map_or(DiagnosticOutput
::Default
, DiagnosticOutput
::Raw
);
207 let Some(matches
) = handle_options(&args
) else { 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 check_cfg
= interface
::parse_check_cfg(matches
.opt_strs("check-cfg"));
218 let (odir
, ofile
) = make_output(&matches
);
219 let mut config
= interface
::Config
{
222 crate_check_cfg
: check_cfg
,
223 input
: Input
::File(PathBuf
::new()),
229 lint_caps
: Default
::default(),
230 parse_sess_created
: None
,
231 register_lints
: None
,
232 override_queries
: None
,
233 make_codegen_backend
,
234 registry
: diagnostics_registry(),
237 match make_input(config
.opts
.error_format
, &matches
.free
) {
238 Err(reported
) => return Err(reported
),
239 Ok(Some((input
, input_file_path
))) => {
240 config
.input
= input
;
241 config
.input_path
= input_file_path
;
243 callbacks
.config(&mut config
);
245 Ok(None
) => match matches
.free
.len() {
247 callbacks
.config(&mut config
);
248 interface
::run_compiler(config
, |compiler
| {
249 let sopts
= &compiler
.session().opts
;
250 if sopts
.describe_lints
{
251 let mut lint_store
= rustc_lint
::new_lint_store(
252 sopts
.debugging_opts
.no_interleave_lints
,
253 compiler
.session().unstable_options(),
255 let registered_lints
=
256 if let Some(register_lints
) = compiler
.register_lints() {
257 register_lints(compiler
.session(), &mut lint_store
);
262 describe_lints(compiler
.session(), &lint_store
, registered_lints
);
265 let should_stop
= print_crate_info(
266 &***compiler
.codegen_backend(),
269 compiler
.output_dir(),
270 compiler
.output_file(),
271 compiler
.temps_dir(),
274 if should_stop
== Compilation
::Stop
{
277 early_error(sopts
.error_format
, "no input filename given")
281 1 => panic
!("make_input should have provided valid inputs"),
283 config
.opts
.error_format
,
285 "multiple input filenames provided (first two filenames are `{}` and `{}`)",
286 matches
.free
[0], matches
.free
[1],
292 interface
::run_compiler(config
, |compiler
| {
293 let sess
= compiler
.session();
294 let should_stop
= print_crate_info(
295 &***compiler
.codegen_backend(),
297 Some(compiler
.input()),
298 compiler
.output_dir(),
299 compiler
.output_file(),
300 compiler
.temps_dir(),
303 list_metadata(sess
, &*compiler
.codegen_backend().metadata_loader(), compiler
.input())
305 .and_then(|| try_process_rlink(sess
, compiler
));
307 if should_stop
== Compilation
::Stop
{
308 return sess
.compile_status();
311 let linker
= compiler
.enter(|queries
| {
312 let early_exit
= || sess
.compile_status().map(|_
| None
);
315 if let Some(ppm
) = &sess
.opts
.pretty
{
316 if ppm
.needs_ast_map() {
317 let expanded_crate
= queries
.expansion()?
.peek().0.clone();
318 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
319 pretty
::print_after_hir_lowering(
324 compiler
.output_file().as_ref().map(|p
| &**p
),
329 let krate
= queries
.parse()?
.take();
330 pretty
::print_after_parsing(
335 compiler
.output_file().as_ref().map(|p
| &**p
),
338 trace
!("finished pretty-printing");
342 if callbacks
.after_parsing(compiler
, queries
) == Compilation
::Stop
{
346 if sess
.opts
.debugging_opts
.parse_only
347 || sess
.opts
.debugging_opts
.show_span
.is_some()
348 || sess
.opts
.debugging_opts
.ast_json_noexpand
354 let (_
, lint_store
) = &*queries
.register_plugins()?
.peek();
356 // Lint plugins are registered; now we can process command line flags.
357 if sess
.opts
.describe_lints
{
358 describe_lints(sess
, lint_store
, true);
363 queries
.expansion()?
;
364 if callbacks
.after_expansion(compiler
, queries
) == Compilation
::Stop
{
368 queries
.prepare_outputs()?
;
370 if sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
)
371 && sess
.opts
.output_types
.len() == 1
376 queries
.global_ctxt()?
;
378 if sess
.opts
.debugging_opts
.no_analysis
|| sess
.opts
.debugging_opts
.ast_json
{
382 queries
.global_ctxt()?
.peek_mut().enter(|tcx
| {
383 let result
= tcx
.analysis(());
384 if sess
.opts
.debugging_opts
.save_analysis
{
385 let crate_name
= queries
.crate_name()?
.peek().clone();
386 sess
.time("save_analysis", || {
393 compiler
.output_dir().as_ref().map(|p
| &**p
),
402 if callbacks
.after_analysis(compiler
, queries
) == Compilation
::Stop
{
406 queries
.ongoing_codegen()?
;
408 if sess
.opts
.debugging_opts
.print_type_sizes
{
409 sess
.code_stats
.print_type_sizes();
412 let linker
= queries
.linker()?
;
416 if let Some(linker
) = linker
{
417 let _timer
= sess
.timer("link");
421 if sess
.opts
.debugging_opts
.perf_stats
{
422 sess
.print_perf_stats();
425 if sess
.opts
.debugging_opts
.print_fuel
.is_some() {
427 "Fuel used by {}: {}",
428 sess
.opts
.debugging_opts
.print_fuel
.as_ref().unwrap(),
429 sess
.print_fuel
.load(SeqCst
)
438 pub fn set_sigpipe_handler() {
440 // Set the SIGPIPE signal handler, so that an EPIPE
441 // will cause rustc to terminate, as expected.
442 assert_ne
!(libc
::signal(libc
::SIGPIPE
, libc
::SIG_DFL
), libc
::SIG_ERR
);
447 pub fn set_sigpipe_handler() {}
449 // Extract output directory and file from matches.
450 fn make_output(matches
: &getopts
::Matches
) -> (Option
<PathBuf
>, Option
<PathBuf
>) {
451 let odir
= matches
.opt_str("out-dir").map(|o
| PathBuf
::from(&o
));
452 let ofile
= matches
.opt_str("o").map(|o
| PathBuf
::from(&o
));
456 // Extract input (string or file and optional path) from matches.
458 error_format
: ErrorOutputType
,
459 free_matches
: &[String
],
460 ) -> Result
<Option
<(Input
, Option
<PathBuf
>)>, ErrorGuaranteed
> {
461 if free_matches
.len() == 1 {
462 let ifile
= &free_matches
[0];
464 let mut src
= String
::new();
465 if io
::stdin().read_to_string(&mut src
).is_err() {
466 // Immediately stop compilation if there was an issue reading
467 // the input (for example if the input stream is not UTF-8).
468 let reported
= early_error_no_abort(
470 "couldn't read from stdin, as it did not contain valid UTF-8",
472 return Err(reported
);
474 if let Ok(path
) = env
::var("UNSTABLE_RUSTDOC_TEST_PATH") {
475 let line
= env
::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
476 "when UNSTABLE_RUSTDOC_TEST_PATH is set \
477 UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
479 let line
= isize::from_str_radix(&line
, 10)
480 .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
481 let file_name
= FileName
::doc_test_source_code(PathBuf
::from(path
), line
);
482 Ok(Some((Input
::Str { name: file_name, input: src }
, None
)))
484 Ok(Some((Input
::Str { name: FileName::anon_source_code(&src), input: src }
, None
)))
487 Ok(Some((Input
::File(PathBuf
::from(ifile
)), Some(PathBuf
::from(ifile
)))))
494 /// Whether to stop or continue compilation.
495 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
496 pub enum Compilation
{
502 pub fn and_then
<F
: FnOnce() -> Compilation
>(self, next
: F
) -> Compilation
{
504 Compilation
::Stop
=> Compilation
::Stop
,
505 Compilation
::Continue
=> next(),
510 fn handle_explain(registry
: Registry
, code
: &str, output
: ErrorOutputType
) {
511 let upper_cased_code
= code
.to_ascii_uppercase();
512 let normalised
= if upper_cased_code
.starts_with('E'
) {
515 format
!("E{0:0>4}", code
)
517 match registry
.try_find_description(&normalised
) {
518 Ok(Some(description
)) => {
519 let mut is_in_code_block
= false;
520 let mut text
= String
::new();
521 // Slice off the leading newline and print.
522 for line
in description
.lines() {
524 line
.find(|c
: char| !c
.is_whitespace()).unwrap_or_else(|| line
.len());
525 let dedented_line
= &line
[indent_level
..];
526 if dedented_line
.starts_with("```") {
527 is_in_code_block
= !is_in_code_block
;
528 text
.push_str(&line
[..(indent_level
+ 3)]);
529 } else if is_in_code_block
&& dedented_line
.starts_with("# ") {
537 show_content_with_pager(&text
);
543 early_error(output
, &format
!("no extended information for {}", code
));
545 Err(InvalidErrorCode
) => {
546 early_error(output
, &format
!("{} is not a valid error code", code
));
551 fn show_content_with_pager(content
: &str) {
552 let pager_name
= env
::var_os("PAGER").unwrap_or_else(|| {
553 if cfg
!(windows
) { OsString::from("more.com") }
else { OsString::from("less") }
556 let mut fallback_to_println
= false;
558 match Command
::new(pager_name
).stdin(Stdio
::piped()).spawn() {
560 if let Some(pipe
) = pager
.stdin
.as_mut() {
561 if pipe
.write_all(content
.as_bytes()).is_err() {
562 fallback_to_println
= true;
566 if pager
.wait().is_err() {
567 fallback_to_println
= true;
571 fallback_to_println
= true;
575 // If pager fails for whatever reason, we should still print the content
576 // to standard output
577 if fallback_to_println
{
578 print
!("{}", content
);
582 pub fn try_process_rlink(sess
: &Session
, compiler
: &interface
::Compiler
) -> Compilation
{
583 if sess
.opts
.debugging_opts
.link_only
{
584 if let Input
::File(file
) = compiler
.input() {
585 // FIXME: #![crate_type] and #![crate_name] support not implemented yet
586 sess
.init_crate_types(collect_crate_types(sess
, &[]));
587 let outputs
= compiler
.build_output_filenames(sess
, &[]);
588 let rlink_data
= fs
::read(file
).unwrap_or_else(|err
| {
589 sess
.fatal(&format
!("failed to read rlink file: {}", err
));
591 let codegen_results
= match CodegenResults
::deserialize_rlink(rlink_data
) {
592 Ok(codegen
) => codegen
,
594 sess
.fatal(&format
!("Could not deserialize .rlink file: {error}"));
597 let result
= compiler
.codegen_backend().link(sess
, codegen_results
, &outputs
);
598 abort_on_err(result
, sess
);
600 sess
.fatal("rlink must be a file")
604 Compilation
::Continue
608 pub fn list_metadata(
610 metadata_loader
: &dyn MetadataLoader
,
613 if sess
.opts
.debugging_opts
.ls
{
615 Input
::File(ref ifile
) => {
616 let path
= &(*ifile
);
617 let mut v
= Vec
::new();
618 locator
::list_file_metadata(&sess
.target
, path
, metadata_loader
, &mut v
).unwrap();
619 println
!("{}", String
::from_utf8(v
).unwrap());
621 Input
::Str { .. }
=> {
622 early_error(ErrorOutputType
::default(), "cannot list metadata for stdin");
625 return Compilation
::Stop
;
628 Compilation
::Continue
632 codegen_backend
: &dyn CodegenBackend
,
634 input
: Option
<&Input
>,
635 odir
: &Option
<PathBuf
>,
636 ofile
: &Option
<PathBuf
>,
637 temps_dir
: &Option
<PathBuf
>,
639 use rustc_session
::config
::PrintRequest
::*;
640 // NativeStaticLibs and LinkArgs are special - printed during linking
641 // (empty iterator returns true)
642 if sess
.opts
.prints
.iter().all(|&p
| p
== NativeStaticLibs
|| p
== LinkArgs
) {
643 return Compilation
::Continue
;
646 let attrs
= match input
{
649 let result
= parse_crate_attrs(sess
, input
);
651 Ok(attrs
) => Some(attrs
),
652 Err(mut parse_error
) => {
654 return Compilation
::Stop
;
659 for req
in &sess
.opts
.prints
{
662 let mut targets
= rustc_target
::spec
::TARGETS
.iter().copied().collect
::<Vec
<_
>>();
663 targets
.sort_unstable();
664 println
!("{}", targets
.join("\n"));
666 Sysroot
=> println
!("{}", sess
.sysroot
.display()),
667 TargetLibdir
=> println
!("{}", sess
.target_tlib_path
.dir
.display()),
668 TargetSpec
=> println
!("{}", sess
.target
.to_json().pretty()),
669 FileNames
| CrateName
=> {
670 let input
= input
.unwrap_or_else(|| {
671 early_error(ErrorOutputType
::default(), "no input file provided")
673 let attrs
= attrs
.as_ref().unwrap();
674 let t_outputs
= rustc_interface
::util
::build_output_filenames(
675 input
, odir
, ofile
, temps_dir
, attrs
, sess
,
677 let id
= rustc_session
::output
::find_crate_name(sess
, attrs
, input
);
678 if *req
== PrintRequest
::CrateName
{
682 let crate_types
= collect_crate_types(sess
, attrs
);
683 for &style
in &crate_types
{
685 rustc_session
::output
::filename_for_input(sess
, style
, &id
, &t_outputs
);
686 println
!("{}", fname
.file_name().unwrap().to_string_lossy());
694 .filter_map(|&(name
, value
)| {
695 // Note that crt-static is a specially recognized cfg
696 // directive that's printed out here as part of
697 // rust-lang/rust#37406, but in general the
698 // `target_feature` cfg is gated under
699 // rust-lang/rust#29717. For now this is just
700 // specifically allowing the crt-static cfg and that's
701 // it, this is intended to get into Cargo and then go
702 // through to build scripts.
703 if (name
!= sym
::target_feature
|| value
!= Some(sym
::crt_dash_static
))
704 && !sess
.is_nightly_build()
705 && find_gated_cfg(|cfg_sym
| cfg_sym
== name
).is_some()
710 if let Some(value
) = value
{
711 Some(format
!("{}=\"{}\"", name
, value
))
713 Some(name
.to_string())
716 .collect
::<Vec
<String
>>();
727 | StackProtectorStrategies
728 | TargetFeatures
=> {
729 codegen_backend
.print(*req
, sess
);
731 // Any output here interferes with Cargo's parsing of other printed output
732 NativeStaticLibs
=> {}
739 /// Prints version information
740 pub fn version(binary
: &str, matches
: &getopts
::Matches
) {
741 let verbose
= matches
.opt_present("verbose");
743 println
!("{} {}", binary
, util
::version_str().unwrap_or("unknown version"));
746 fn unw(x
: Option
<&str>) -> &str {
747 x
.unwrap_or("unknown")
749 println
!("binary: {}", binary
);
750 println
!("commit-hash: {}", unw(util
::commit_hash_str()));
751 println
!("commit-date: {}", unw(util
::commit_date_str()));
752 println
!("host: {}", config
::host_triple());
753 println
!("release: {}", unw(util
::release_str()));
755 let debug_flags
= matches
.opt_strs("Z");
756 let backend_name
= debug_flags
.iter().find_map(|x
| x
.strip_prefix("codegen-backend="));
757 get_codegen_backend(&None
, backend_name
).print_version();
761 fn usage(verbose
: bool
, include_unstable_options
: bool
, nightly_build
: bool
) {
762 let groups
= if verbose { config::rustc_optgroups() }
else { config::rustc_short_optgroups() }
;
763 let mut options
= getopts
::Options
::new();
764 for option
in groups
.iter().filter(|x
| include_unstable_options
|| x
.is_stable()) {
765 (option
.apply
)(&mut options
);
767 let message
= "Usage: rustc [OPTIONS] INPUT";
768 let nightly_help
= if nightly_build
{
769 "\n -Z help Print unstable compiler options"
773 let verbose_help
= if verbose
{
776 "\n --help -v Print the full set of options rustc accepts"
778 let at_path
= if verbose
{
779 " @path Read newline separated options from `path`\n"
784 "{options}{at_path}\nAdditional help:
785 -C help Print codegen options
787 Print 'lint' options and default settings{nightly}{verbose}\n",
788 options
= options
.usage(message
),
790 nightly
= nightly_help
,
791 verbose
= verbose_help
795 fn print_wall_help() {
798 The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
799 default. Use `rustc -W help` to see all available lints. It's more common to put
800 warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
801 the command line flag directly.
806 /// Write to stdout lint command options, together with a list of all available lints
807 pub fn describe_lints(sess
: &Session
, lint_store
: &LintStore
, loaded_plugins
: bool
) {
810 Available lint options:
811 -W <foo> Warn about <foo>
815 -F <foo> Forbid <foo> \
816 (deny <foo> and all attempts to override)
821 fn sort_lints(sess
: &Session
, mut lints
: Vec
<&'
static Lint
>) -> Vec
<&'
static Lint
> {
822 // The sort doesn't case-fold but it's doubtful we care.
823 lints
.sort_by_cached_key(|x
: &&Lint
| (x
.default_level(sess
.edition()), x
.name
));
828 lints
: Vec
<(&'
static str, Vec
<LintId
>, bool
)>,
829 ) -> Vec
<(&'
static str, Vec
<LintId
>)> {
830 let mut lints
: Vec
<_
> = lints
.into_iter().map(|(x
, y
, _
)| (x
, y
)).collect();
831 lints
.sort_by_key(|l
| l
.0);
835 let (plugin
, builtin
): (Vec
<_
>, _
) =
836 lint_store
.get_lints().iter().cloned().partition(|&lint
| lint
.is_plugin
);
837 let plugin
= sort_lints(sess
, plugin
);
838 let builtin
= sort_lints(sess
, builtin
);
840 let (plugin_groups
, builtin_groups
): (Vec
<_
>, _
) =
841 lint_store
.get_lint_groups().partition(|&(.., p
)| p
);
842 let plugin_groups
= sort_lint_groups(plugin_groups
);
843 let builtin_groups
= sort_lint_groups(builtin_groups
);
846 plugin
.iter().chain(&builtin
).map(|&s
| s
.name
.chars().count()).max().unwrap_or(0);
847 let padded
= |x
: &str| {
848 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
853 println
!("Lint checks provided by rustc:\n");
854 println
!(" {} {:7.7} {}", padded("name"), "default", "meaning");
855 println
!(" {} {:7.7} {}", padded("----"), "-------", "-------");
857 let print_lints
= |lints
: Vec
<&Lint
>| {
859 let name
= lint
.name_lower().replace('_'
, "-");
863 lint
.default_level(sess
.edition()).as_str(),
870 print_lints(builtin
);
872 let max_name_len
= max(
876 .chain(&builtin_groups
)
877 .map(|&(s
, _
)| s
.chars().count())
882 let padded
= |x
: &str| {
883 let mut s
= " ".repeat(max_name_len
- x
.chars().count());
888 println
!("Lint groups provided by rustc:\n");
889 println
!(" {} sub-lints", padded("name"));
890 println
!(" {} ---------", padded("----"));
891 println
!(" {} all lints that are set to issue warnings", padded("warnings"));
893 let print_lint_groups
= |lints
: Vec
<(&'
static str, Vec
<LintId
>)>| {
894 for (name
, to
) in lints
{
895 let name
= name
.to_lowercase().replace('_'
, "-");
898 .map(|x
| x
.to_string().replace('_'
, "-"))
899 .collect
::<Vec
<String
>>()
901 println
!(" {} {}", padded(&name
), desc
);
906 print_lint_groups(builtin_groups
);
908 match (loaded_plugins
, plugin
.len(), plugin_groups
.len()) {
909 (false, 0, _
) | (false, _
, 0) => {
910 println
!("Lint tools like Clippy can provide additional lints and lint groups.");
912 (false, ..) => panic
!("didn't load lint plugins but got them anyway!"),
913 (true, 0, 0) => println
!("This crate does not load any lint plugins or lint groups."),
916 println
!("Lint checks provided by plugins loaded by this crate:\n");
920 println
!("Lint groups provided by plugins loaded by this crate:\n");
921 print_lint_groups(plugin_groups
);
927 fn describe_debug_flags() {
928 println
!("\nAvailable options:\n");
929 print_flag_list("-Z", config
::DB_OPTIONS
);
932 fn describe_codegen_flags() {
933 println
!("\nAvailable codegen options:\n");
934 print_flag_list("-C", config
::CG_OPTIONS
);
937 fn print_flag_list
<T
>(
939 flag_list
: &[(&'
static str, T
, &'
static str, &'
static str)],
941 let max_len
= flag_list
.iter().map(|&(name
, _
, _
, _
)| name
.chars().count()).max().unwrap_or(0);
943 for &(name
, _
, _
, desc
) in flag_list
{
945 " {} {:>width$}=val -- {}",
947 name
.replace('_'
, "-"),
954 /// Process command line options. Emits messages as appropriate. If compilation
955 /// should continue, returns a getopts::Matches object parsed from args,
956 /// otherwise returns `None`.
958 /// The compiler's handling of options is a little complicated as it ties into
959 /// our stability story. The current intention of each compiler option is to
960 /// have one of two modes:
962 /// 1. An option is stable and can be used everywhere.
963 /// 2. An option is unstable, and can only be used on nightly.
965 /// Like unstable library and language features, however, unstable options have
966 /// always required a form of "opt in" to indicate that you're using them. This
967 /// provides the easy ability to scan a code base to check to see if anything
968 /// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
970 /// All options behind `-Z` are considered unstable by default. Other top-level
971 /// options can also be considered unstable, and they were unlocked through the
972 /// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
973 /// instability in both cases, though.
975 /// So with all that in mind, the comments below have some more detail about the
976 /// contortions done here to get things to work out correctly.
977 pub fn handle_options(args
: &[String
]) -> Option
<getopts
::Matches
> {
978 // Throw away the first argument, the name of the binary
979 let args
= &args
[1..];
982 // user did not write `-v` nor `-Z unstable-options`, so do not
983 // include that extra information.
985 rustc_feature
::UnstableFeatures
::from_environment(None
).is_nightly_build();
986 usage(false, false, nightly_build
);
990 // Parse with *all* options defined in the compiler, we don't worry about
991 // option stability here we just want to parse as much as possible.
992 let mut options
= getopts
::Options
::new();
993 for option
in config
::rustc_optgroups() {
994 (option
.apply
)(&mut options
);
996 let matches
= options
.parse(args
).unwrap_or_else(|e
| {
998 getopts
::Fail
::UnrecognizedOption(ref opt
) => CG_OPTIONS
1000 .map(|&(name
, ..)| ('C'
, name
))
1001 .chain(DB_OPTIONS
.iter().map(|&(name
, ..)| ('Z'
, name
)))
1002 .find(|&(_
, name
)| *opt
== name
.replace('_'
, "-"))
1003 .map(|(flag
, _
)| format
!("{}. Did you mean `-{} {}`?", e
, flag
, opt
)),
1006 early_error(ErrorOutputType
::default(), &msg
.unwrap_or_else(|| e
.to_string()));
1009 // For all options we just parsed, we check a few aspects:
1011 // * If the option is stable, we're all good
1012 // * If the option wasn't passed, we're all good
1013 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
1014 // ourselves), then we require the `-Z unstable-options` flag to unlock
1015 // this option that was passed.
1016 // * If we're a nightly compiler, then unstable options are now unlocked, so
1017 // we're good to go.
1018 // * Otherwise, if we're an unstable option then we generate an error
1019 // (unstable option being used on stable)
1020 nightly_options
::check_nightly_options(&matches
, &config
::rustc_optgroups());
1022 if matches
.opt_present("h") || matches
.opt_present("help") {
1023 // Only show unstable options in --help if we accept unstable options.
1024 let unstable_enabled
= nightly_options
::is_unstable_enabled(&matches
);
1025 let nightly_build
= nightly_options
::match_is_nightly_build(&matches
);
1026 usage(matches
.opt_present("verbose"), unstable_enabled
, nightly_build
);
1030 // Handle the special case of -Wall.
1031 let wall
= matches
.opt_strs("W");
1032 if wall
.iter().any(|x
| *x
== "all") {
1034 rustc_errors
::FatalError
.raise();
1037 // Don't handle -W help here, because we might first load plugins.
1038 let debug_flags
= matches
.opt_strs("Z");
1039 if debug_flags
.iter().any(|x
| *x
== "help") {
1040 describe_debug_flags();
1044 let cg_flags
= matches
.opt_strs("C");
1046 if cg_flags
.iter().any(|x
| *x
== "help") {
1047 describe_codegen_flags();
1051 if cg_flags
.iter().any(|x
| *x
== "no-stack-check") {
1053 ErrorOutputType
::default(),
1054 "the --no-stack-check flag is deprecated and does nothing",
1058 if cg_flags
.iter().any(|x
| *x
== "passes=list") {
1059 let backend_name
= debug_flags
.iter().find_map(|x
| {
1060 if x
.starts_with("codegen-backend=") {
1061 Some(&x
["codegen-backends=".len()..])
1066 get_codegen_backend(&None
, backend_name
).print_passes();
1070 if matches
.opt_present("version") {
1071 version("rustc", &matches
);
1078 fn parse_crate_attrs
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
1080 Input
::File(ifile
) => rustc_parse
::parse_crate_attrs_from_file(ifile
, &sess
.parse_sess
),
1081 Input
::Str { name, input }
=> rustc_parse
::parse_crate_attrs_from_source_str(
1089 /// Gets a list of extra command-line flags provided by the user, as strings.
1091 /// This function is used during ICEs to show more information useful for
1092 /// debugging, since some ICEs only happens with non-default compiler flags
1093 /// (and the users don't always report them).
1094 fn extra_compiler_flags() -> Option
<(Vec
<String
>, bool
)> {
1095 let mut args
= env
::args_os().map(|arg
| arg
.to_string_lossy().to_string()).peekable();
1097 let mut result
= Vec
::new();
1098 let mut excluded_cargo_defaults
= false;
1099 while let Some(arg
) = args
.next() {
1100 if let Some(a
) = ICE_REPORT_COMPILER_FLAGS
.iter().find(|a
| arg
.starts_with(*a
)) {
1101 let content
= if arg
.len() == a
.len() {
1103 Some(arg
) => arg
.to_string(),
1106 } else if arg
.get(a
.len()..a
.len() + 1) == Some("=") {
1107 arg
[a
.len() + 1..].to_string()
1109 arg
[a
.len()..].to_string()
1111 if ICE_REPORT_COMPILER_FLAGS_EXCLUDE
.iter().any(|exc
| content
.starts_with(exc
)) {
1112 excluded_cargo_defaults
= true;
1114 result
.push(a
.to_string());
1115 match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE
.iter().find(|s
| content
.starts_with(*s
))
1117 Some(s
) => result
.push(s
.to_string()),
1118 None
=> result
.push(content
),
1124 if !result
.is_empty() { Some((result, excluded_cargo_defaults)) }
else { None }
1127 /// Runs a closure and catches unwinds triggered by fatal errors.
1129 /// The compiler currently unwinds with a special sentinel value to abort
1130 /// compilation on fatal errors. This function catches that sentinel and turns
1131 /// the panic into a `Result` instead.
1132 pub fn catch_fatal_errors
<F
: FnOnce() -> R
, R
>(f
: F
) -> Result
<R
, ErrorGuaranteed
> {
1133 catch_unwind(panic
::AssertUnwindSafe(f
)).map_err(|value
| {
1134 if value
.is
::<rustc_errors
::FatalErrorMarker
>() {
1135 ErrorGuaranteed
::unchecked_claim_error_was_emitted()
1137 panic
::resume_unwind(value
);
1142 /// Variant of `catch_fatal_errors` for the `interface::Result` return type
1143 /// that also computes the exit code.
1144 pub fn catch_with_exit_code(f
: impl FnOnce() -> interface
::Result
<()>) -> i32 {
1145 let result
= catch_fatal_errors(f
).and_then(|result
| result
);
1147 Ok(()) => EXIT_SUCCESS
,
1148 Err(_
) => EXIT_FAILURE
,
1152 static DEFAULT_HOOK
: SyncLazy
<Box
<dyn Fn(&panic
::PanicInfo
<'_
>) + Sync
+ Send
+ '
static>> =
1154 let hook
= panic
::take_hook();
1155 panic
::set_hook(Box
::new(|info
| {
1156 // Invoke the default handler, which prints the actual panic message and optionally a backtrace
1157 (*DEFAULT_HOOK
)(info
);
1159 // Separate the output with an empty line
1162 // Print the ICE message
1163 report_ice(info
, BUG_REPORT_URL
);
1168 /// Prints the ICE message, including query stack, but without backtrace.
1170 /// The message will point the user at `bug_report_url` to report the ICE.
1172 /// When `install_ice_hook` is called, this function will be called as the panic
1174 pub fn report_ice(info
: &panic
::PanicInfo
<'_
>, bug_report_url
: &str) {
1175 let fallback_bundle
=
1176 rustc_errors
::fallback_fluent_bundle(rustc_errors
::DEFAULT_LOCALE_RESOURCES
, false);
1177 let emitter
= Box
::new(rustc_errors
::emitter
::EmitterWriter
::stderr(
1178 rustc_errors
::ColorConfig
::Auto
,
1187 let handler
= rustc_errors
::Handler
::with_emitter(true, None
, emitter
);
1189 // a .span_bug or .bug call has already printed what
1190 // it wants to print.
1191 if !info
.payload().is
::<rustc_errors
::ExplicitBug
>() {
1192 let mut d
= rustc_errors
::Diagnostic
::new(rustc_errors
::Level
::Bug
, "unexpected panic");
1193 handler
.emit_diagnostic(&mut d
);
1196 let mut xs
: Vec
<Cow
<'
static, str>> = vec
![
1197 "the compiler unexpectedly panicked. this is a bug.".into(),
1198 format
!("we would appreciate a bug report: {}", bug_report_url
).into(),
1200 "rustc {} running on {}",
1201 util
::version_str().unwrap_or("unknown_version"),
1202 config
::host_triple()
1207 if let Some((flags
, excluded_cargo_defaults
)) = extra_compiler_flags() {
1208 xs
.push(format
!("compiler flags: {}", flags
.join(" ")).into());
1210 if excluded_cargo_defaults
{
1211 xs
.push("some of the compiler flags provided by cargo are hidden".into());
1216 handler
.note_without_error(note
.as_ref());
1219 // If backtraces are enabled, also print the query stack
1220 let backtrace
= env
::var_os("RUST_BACKTRACE").map_or(false, |x
| &x
!= "0");
1222 let num_frames
= if backtrace { None }
else { Some(2) }
;
1224 interface
::try_print_query_stack(&handler
, num_frames
);
1228 if env
::var("RUSTC_BREAK_ON_ICE").is_ok() {
1229 // Trigger a debugger if we crashed during bootstrap
1230 winapi
::um
::debugapi
::DebugBreak();
1235 /// Installs a panic hook that will print the ICE message on unexpected panics.
1237 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
1238 pub fn install_ice_hook() {
1239 // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
1240 // full backtraces. When a compiler ICE happens, we want to gather
1241 // as much information as possible to present in the issue opened
1242 // by the user. Compiler developers and other rustc users can
1243 // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
1244 // (e.g. `RUST_BACKTRACE=1`)
1245 if std
::env
::var("RUST_BACKTRACE").is_err() {
1246 std
::env
::set_var("RUST_BACKTRACE", "full");
1248 SyncLazy
::force(&DEFAULT_HOOK
);
1251 /// This allows tools to enable rust logging without having to magically match rustc's
1252 /// tracing crate version.
1253 pub fn init_rustc_env_logger() {
1254 if let Err(error
) = rustc_log
::init_rustc_env_logger() {
1255 early_error(ErrorOutputType
::default(), &error
.to_string());
1259 /// This allows tools to enable rust logging without having to magically match rustc's
1260 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
1261 /// other than `RUSTC_LOG`.
1262 pub fn init_env_logger(env
: &str) {
1263 if let Err(error
) = rustc_log
::init_env_logger(env
) {
1264 early_error(ErrorOutputType
::default(), &error
.to_string());
1268 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
1269 mod signal_handler
{
1271 fn backtrace_symbols_fd(
1272 buffer
: *const *mut libc
::c_void
,
1278 extern "C" fn print_stack_trace(_
: libc
::c_int
) {
1279 const MAX_FRAMES
: usize = 256;
1280 static mut STACK_TRACE
: [*mut libc
::c_void
; MAX_FRAMES
] =
1281 [std
::ptr
::null_mut(); MAX_FRAMES
];
1283 let depth
= libc
::backtrace(STACK_TRACE
.as_mut_ptr(), MAX_FRAMES
as i32);
1287 backtrace_symbols_fd(STACK_TRACE
.as_ptr(), depth
, 2);
1291 // When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
1292 // process, print a stack trace and then exit.
1293 pub(super) fn install() {
1295 const ALT_STACK_SIZE
: usize = libc
::MINSIGSTKSZ
+ 64 * 1024;
1296 let mut alt_stack
: libc
::stack_t
= std
::mem
::zeroed();
1298 std
::alloc
::alloc(std
::alloc
::Layout
::from_size_align(ALT_STACK_SIZE
, 1).unwrap())
1299 as *mut libc
::c_void
;
1300 alt_stack
.ss_size
= ALT_STACK_SIZE
;
1301 libc
::sigaltstack(&alt_stack
, std
::ptr
::null_mut());
1303 let mut sa
: libc
::sigaction
= std
::mem
::zeroed();
1304 sa
.sa_sigaction
= print_stack_trace
as libc
::sighandler_t
;
1305 sa
.sa_flags
= libc
::SA_NODEFER
| libc
::SA_RESETHAND
| libc
::SA_ONSTACK
;
1306 libc
::sigemptyset(&mut sa
.sa_mask
);
1307 libc
::sigaction(libc
::SIGSEGV
, &sa
, std
::ptr
::null_mut());
1312 #[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
1313 mod signal_handler
{
1314 pub(super) fn install() {}
1317 pub fn main() -> ! {
1318 let start_time
= Instant
::now();
1319 let start_rss
= get_resident_set_size();
1320 init_rustc_env_logger();
1321 signal_handler
::install();
1322 let mut callbacks
= TimePassesCallbacks
::default();
1324 let exit_code
= catch_with_exit_code(|| {
1325 let args
= env
::args_os()
1328 arg
.into_string().unwrap_or_else(|arg
| {
1330 ErrorOutputType
::default(),
1331 &format
!("argument {} is not valid Unicode: {:?}", i
, arg
),
1335 .collect
::<Vec
<_
>>();
1336 RunCompiler
::new(&args
, &mut callbacks
).run()
1339 if callbacks
.time_passes
{
1340 let end_rss
= get_resident_set_size();
1341 print_time_passes_entry("total", start_time
.elapsed(), start_rss
, end_rss
);
1344 process
::exit(exit_code
)