lib.rs 47.1 KB
Newer Older
1 2 3 4 5 6
//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

E
Erik Hofmayer 已提交
7
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
8
#![feature(nll)]
9
#![feature(once_cell)]
M
Mark Rousskov 已提交
10
#![recursion_limit = "256"]
11

J
Jose Narvaez 已提交
12
#[macro_use]
G
Gurpreet Singh 已提交
13
extern crate tracing;
14

15 16
pub extern crate rustc_plugin_impl as plugin;

U
Ujjwal Sharma 已提交
17
use rustc_ast as ast;
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 22
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
23
use rustc_feature::find_gated_cfg;
24
use rustc_hir::def_id::LOCAL_CRATE;
25
use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
M
Mark Rousskov 已提交
26
use rustc_interface::{interface, Queries};
27
use rustc_lint::LintStore;
M
Mark Rousskov 已提交
28
use rustc_metadata::locator;
29
use rustc_middle::middle::cstore::MetadataLoader;
M
Mark Rousskov 已提交
30 31
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
V
Victor Ding 已提交
32
use rustc_serialize::json::{self, ToJson};
33
use rustc_session::config::nightly_options;
D
Dan Aloni 已提交
34
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
L
Luca Barbieri 已提交
35
use rustc_session::getopts;
36 37 38
use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, DiagnosticOutput, Session};
use rustc_session::{early_error, early_warn};
39 40
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
41

42
use std::borrow::Cow;
43
use std::cmp::max;
44
use std::default::Default;
A
Alex Crichton 已提交
45
use std::env;
46
use std::ffi::OsString;
V
Victor Ding 已提交
47
use std::fs;
48
use std::io::{self, Read, Write};
49
use std::lazy::SyncLazy;
50
use std::mem;
51
use std::panic::{self, catch_unwind};
52
use std::path::PathBuf;
53
use std::process::{self, Command, Stdio};
54
use std::str;
55
use std::time::Instant;
N
Nick Cameron 已提交
56

M
Miguel Ojeda 已提交
57
pub mod args;
M
Mark Rousskov 已提交
58
pub mod pretty;
59

60
/// Exit status code used for successful compilation and help output.
61
pub const EXIT_SUCCESS: i32 = 0;
62

63
/// Exit status code used for compilation failures and invalid flags.
64
pub const EXIT_FAILURE: i32 = 1;
65

66 67
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
    ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
68 69 70 71 72 73

const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"];

const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];

const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
74

75
pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T {
76
    match result {
77
        Err(..) => {
78 79 80
            sess.abort_if_errors();
            panic!("error reported but abort_if_errors didn't abort???");
        }
81 82 83 84
        Ok(x) => x,
    }
}

85 86 87
pub trait Callbacks {
    /// Called before creating the compiler instance
    fn config(&mut self, _config: &mut interface::Config) {}
88 89
    /// Called after parsing. Return value instructs the compiler whether to
    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
R
Ralf Jung 已提交
90 91 92 93 94
    fn after_parsing<'tcx>(
        &mut self,
        _compiler: &interface::Compiler,
        _queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
95
        Compilation::Continue
96
    }
97 98
    /// Called after expansion. Return value instructs the compiler whether to
    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
R
Ralf Jung 已提交
99 100 101 102 103
    fn after_expansion<'tcx>(
        &mut self,
        _compiler: &interface::Compiler,
        _queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
104
        Compilation::Continue
105
    }
106 107
    /// Called after analysis. Return value instructs the compiler whether to
    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
R
Ralf Jung 已提交
108 109 110 111 112
    fn after_analysis<'tcx>(
        &mut self,
        _compiler: &interface::Compiler,
        _queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
113
        Compilation::Continue
114
    }
N
Nick Cameron 已提交
115 116
}

117 118 119 120 121 122 123
#[derive(Default)]
pub struct TimePassesCallbacks {
    time_passes: bool,
}

impl Callbacks for TimePassesCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
124 125
        // If a --prints=... option has been given, we don't print the "total"
        // time because it will mess up the --prints output. See #64339.
M
Mark Rousskov 已提交
126 127
        self.time_passes = config.opts.prints.is_empty()
            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
128
        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
129 130 131
    }
}

132 133 134 135
pub fn diagnostics_registry() -> Registry {
    Registry::new(&rustc_error_codes::DIAGNOSTICS)
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
pub struct RunCompiler<'a, 'b> {
    at_args: &'a [String],
    callbacks: &'b mut (dyn Callbacks + Send),
    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
    emitter: Option<Box<dyn Write + Send>>,
    make_codegen_backend:
        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
}

impl<'a, 'b> RunCompiler<'a, 'b> {
    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
        Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
    }
    pub fn set_make_codegen_backend(
        &mut self,
        make_codegen_backend: Option<
            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
        >,
    ) -> &mut Self {
        self.make_codegen_backend = make_codegen_backend;
        self
    }
    pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
        self.emitter = emitter;
        self
    }
    pub fn set_file_loader(
        &mut self,
        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
    ) -> &mut Self {
        self.file_loader = file_loader;
        self
    }
    pub fn run(self) -> interface::Result<()> {
        run_compiler(
            self.at_args,
            self.callbacks,
            self.file_loader,
            self.emitter,
            self.make_codegen_backend,
        )
    }
}
179 180
// Parse args and run the compiler. This is the primary entry point for rustc.
// The FileLoader provides a way to load files from sources other than the file system.
181
fn run_compiler(
182
    at_args: &[String],
183 184
    callbacks: &mut (dyn Callbacks + Send),
    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
M
Mark Rousskov 已提交
185
    emitter: Option<Box<dyn Write + Send>>,
186 187 188
    make_codegen_backend: Option<
        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
    >,
189
) -> interface::Result<()> {
M
Miguel Ojeda 已提交
190 191
    let args = args::arg_expand_all(at_args);

K
Kazantcev Andrey 已提交
192
    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
193
    let matches = match handle_options(&args) {
194
        Some(matches) => matches,
195
        None => return Ok(()),
196
    };
J
John Kåre Alsaker 已提交
197

198
    let sopts = config::build_session_options(&matches);
199
    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
N
Nick Cameron 已提交
200

201 202 203 204 205
    // We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take
    // ownership of it when necessary, while also allowing the non-dummy config to take ownership
    // when `dummy_config` is not used.
    let mut make_codegen_backend = Some(make_codegen_backend);

206 207 208 209 210 211 212 213 214 215 216 217
    let mut dummy_config = |sopts, cfg, diagnostic_output| {
        let mut config = interface::Config {
            opts: sopts,
            crate_cfg: cfg,
            input: Input::File(PathBuf::new()),
            input_path: None,
            output_file: None,
            output_dir: None,
            file_loader: None,
            diagnostic_output,
            stderr: None,
            lint_caps: Default::default(),
218
            parse_sess_created: None,
219
            register_lints: None,
220
            override_queries: None,
221
            make_codegen_backend: make_codegen_backend.take().unwrap(),
222
            registry: diagnostics_registry(),
223 224 225 226
        };
        callbacks.config(&mut config);
        config
    };
227

228
    if let Some(ref code) = matches.opt_str("explain") {
229
        handle_explain(diagnostics_registry(), code, sopts.error_format);
230 231
        return Ok(());
    }
232 233

    let (odir, ofile) = make_output(&matches);
234
    let (input, input_file_path, input_err) = match make_input(&matches.free) {
235
        Some(v) => v,
M
Mark Rousskov 已提交
236 237 238 239 240 241
        None => match matches.free.len() {
            0 => {
                let config = dummy_config(sopts, cfg, diagnostic_output);
                interface::run_compiler(config, |compiler| {
                    let sopts = &compiler.session().opts;
                    if sopts.describe_lints {
242
                        let mut lint_store = rustc_lint::new_lint_store(
M
Mark Rousskov 已提交
243 244
                            sopts.debugging_opts.no_interleave_lints,
                            compiler.session().unstable_options(),
245
                        );
246 247 248 249 250 251 252 253
                        let registered_lints =
                            if let Some(register_lints) = compiler.register_lints() {
                                register_lints(compiler.session(), &mut lint_store);
                                true
                            } else {
                                false
                            };
                        describe_lints(compiler.session(), &lint_store, registered_lints);
M
Mark Rousskov 已提交
254 255 256 257 258 259 260 261 262
                        return;
                    }
                    let should_stop = RustcDefaultCalls::print_crate_info(
                        &***compiler.codegen_backend(),
                        compiler.session(),
                        None,
                        &odir,
                        &ofile,
                    );
N
Nick Cameron 已提交
263

M
Mark Rousskov 已提交
264 265 266 267 268 269
                    if should_stop == Compilation::Stop {
                        return;
                    }
                    early_error(sopts.error_format, "no input filename given")
                });
                return Ok(());
270
            }
M
Mark Rousskov 已提交
271 272 273 274 275 276 277 278 279
            1 => panic!("make_input should have provided valid inputs"),
            _ => early_error(
                sopts.error_format,
                &format!(
                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
                    matches.free[0], matches.free[1],
                ),
            ),
        },
280
    };
281

282 283 284
    if let Some(err) = input_err {
        // Immediately stop compilation if there was an issue reading
        // the input (for example if the input stream is not UTF-8).
285 286 287 288
        interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| {
            compiler.session().err(&err.to_string());
        });
        return Err(ErrorReported);
289 290
    }

291 292 293 294 295 296 297 298 299 300 301
    let mut config = interface::Config {
        opts: sopts,
        crate_cfg: cfg,
        input,
        input_path: input_file_path,
        output_file: ofile,
        output_dir: odir,
        file_loader,
        diagnostic_output,
        stderr: None,
        lint_caps: Default::default(),
302
        parse_sess_created: None,
303
        register_lints: None,
304
        override_queries: None,
305
        make_codegen_backend: make_codegen_backend.unwrap(),
306
        registry: diagnostics_registry(),
307 308 309 310 311 312 313 314 315 316 317 318
    };

    callbacks.config(&mut config);

    interface::run_compiler(config, |compiler| {
        let sess = compiler.session();
        let should_stop = RustcDefaultCalls::print_crate_info(
            &***compiler.codegen_backend(),
            sess,
            Some(compiler.input()),
            compiler.output_dir(),
            compiler.output_file(),
M
Mark Rousskov 已提交
319 320 321 322 323 324 325 326
        )
        .and_then(|| {
            RustcDefaultCalls::list_metadata(
                sess,
                &*compiler.codegen_backend().metadata_loader(),
                &matches,
                compiler.input(),
            )
V
Victor Ding 已提交
327 328
        })
        .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
329 330 331 332 333

        if should_stop == Compilation::Stop {
            return sess.compile_status();
        }

334
        let linker = compiler.enter(|queries| {
C
Camille GILLOT 已提交
335
            let early_exit = || sess.compile_status().map(|_| None);
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
            queries.parse()?;

            if let Some(ppm) = &sess.opts.pretty {
                if ppm.needs_ast_map() {
                    queries.global_ctxt()?.peek_mut().enter(|tcx| {
                        let expanded_crate = queries.expansion()?.take().0;
                        pretty::print_after_hir_lowering(
                            tcx,
                            compiler.input(),
                            &expanded_crate,
                            *ppm,
                            compiler.output_file().as_ref().map(|p| &**p),
                        );
                        Ok(())
                    })?;
                } else {
                    let krate = queries.parse()?.take();
                    pretty::print_after_parsing(
                        sess,
                        &compiler.input(),
                        &krate,
357
                        *ppm,
358 359
                        compiler.output_file().as_ref().map(|p| &**p),
                    );
360
                }
J
Joshua Nelson 已提交
361
                trace!("finished pretty-printing");
C
Camille GILLOT 已提交
362
                return early_exit();
363
            }
364

R
Ralf Jung 已提交
365
            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
366
                return early_exit();
367
            }
N
Nick Cameron 已提交
368

M
Mark Rousskov 已提交
369 370 371 372 373
            if sess.opts.debugging_opts.parse_only
                || sess.opts.debugging_opts.show_span.is_some()
                || sess.opts.debugging_opts.ast_json_noexpand
            {
                return early_exit();
374
            }
375

376 377
            {
                let (_, lint_store) = &*queries.register_plugins()?.peek();
378

379 380 381
                // Lint plugins are registered; now we can process command line flags.
                if sess.opts.describe_lints {
                    describe_lints(&sess, &lint_store, true);
C
Camille GILLOT 已提交
382
                    return early_exit();
383 384 385 386
                }
            }

            queries.expansion()?;
R
Ralf Jung 已提交
387
            if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
388
                return early_exit();
389
            }
390

391 392 393 394 395
            queries.prepare_outputs()?;

            if sess.opts.output_types.contains_key(&OutputType::DepInfo)
                && sess.opts.output_types.len() == 1
            {
C
Camille GILLOT 已提交
396
                return early_exit();
397
            }
398

399
            queries.global_ctxt()?;
400

401
            // Drop AST after creating GlobalCtxt to free memory
402 403 404 405
            {
                let _timer = sess.prof.generic_activity("drop_ast");
                mem::drop(queries.expansion()?.take());
            }
406

M
Mark Rousskov 已提交
407 408
            if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
                return early_exit();
409
            }
410

411 412 413 414 415
            if sess.opts.debugging_opts.save_analysis {
                let crate_name = queries.crate_name()?.peek().clone();
                queries.global_ctxt()?.peek_mut().enter(|tcx| {
                    let result = tcx.analysis(LOCAL_CRATE);

416
                    sess.time("save_analysis", || {
417 418 419 420 421
                        save::process_crate(
                            tcx,
                            &crate_name,
                            &compiler.input(),
                            None,
C
Tidy.  
Camille GILLOT 已提交
422
                            DumpHandler::new(
M
Mark Rousskov 已提交
423 424 425
                                compiler.output_dir().as_ref().map(|p| &**p),
                                &crate_name,
                            ),
426 427
                        )
                    });
428

429 430 431
                    result
                })?;
            }
432

433
            queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
434

R
Ralf Jung 已提交
435
            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
436
                return early_exit();
437
            }
438

439
            queries.ongoing_codegen()?;
440

441 442 443
            if sess.opts.debugging_opts.print_type_sizes {
                sess.code_stats.print_type_sizes();
            }
444

445 446
            let linker = queries.linker()?;
            Ok(Some(linker))
447
        })?;
448

449
        if let Some(linker) = linker {
J
John Kåre Alsaker 已提交
450
            let _timer = sess.timer("link");
451 452 453
            linker.link()?
        }

454 455 456 457 458
        if sess.opts.debugging_opts.perf_stats {
            sess.print_perf_stats();
        }

        if sess.print_fuel_crate.is_some() {
M
Mark Rousskov 已提交
459 460
            eprintln!(
                "Fuel used by {}: {}",
461
                sess.print_fuel_crate.as_ref().unwrap(),
M
Mark Rousskov 已提交
462 463
                sess.print_fuel.load(SeqCst)
            );
464
        }
465

466 467
        Ok(())
    })
468 469
}

470 471 472 473 474
#[cfg(unix)]
pub fn set_sigpipe_handler() {
    unsafe {
        // Set the SIGPIPE signal handler, so that an EPIPE
        // will cause rustc to terminate, as expected.
L
ljedrz 已提交
475
        assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR);
476 477 478 479 480 481
    }
}

#[cfg(windows)]
pub fn set_sigpipe_handler() {}

482
// Extract output directory and file from matches.
A
Alex Crichton 已提交
483
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
A
Aaron Turon 已提交
484 485
    let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
    let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
486 487
    (odir, ofile)
}
488

489
// Extract input (string or file and optional path) from matches.
490
fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
491
    if free_matches.len() == 1 {
492
        let ifile = &free_matches[0];
493
        if ifile == "-" {
494
            let mut src = String::new();
495
            let err = if io::stdin().read_to_string(&mut src).is_err() {
M
Mark Rousskov 已提交
496 497 498 499
                Some(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "couldn't read from stdin, as it did not contain valid UTF-8",
                ))
500 501 502
            } else {
                None
            };
503
            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
M
Mark Rousskov 已提交
504 505 506 507 508 509
                let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
                    "when UNSTABLE_RUSTDOC_TEST_PATH is set \
                                    UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
                );
                let line = isize::from_str_radix(&line, 10)
                    .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
510 511 512
                let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
                return Some((Input::Str { name: file_name, input: src }, None, err));
            }
M
Mark Rousskov 已提交
513
            Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None, err))
514
        } else {
M
Mark Rousskov 已提交
515
            Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)), None))
516 517 518
        }
    } else {
        None
519
    }
520
}
521

N
Nick Cameron 已提交
522
// Whether to stop or continue compilation.
N
Niko Matsakis 已提交
523
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
N
Nick Cameron 已提交
524 525 526 527 528 529 530 531 532
pub enum Compilation {
    Stop,
    Continue,
}

impl Compilation {
    pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
        match self {
            Compilation::Stop => Compilation::Stop,
J
Jose Narvaez 已提交
533
            Compilation::Continue => next(),
N
Nick Cameron 已提交
534 535 536 537
        }
    }
}

538
/// CompilerCalls instance for a regular rustc build.
N
Niko Matsakis 已提交
539
#[derive(Copy, Clone)]
540 541
pub struct RustcDefaultCalls;

542
fn stdout_isatty() -> bool {
543
    atty::is(atty::Stream::Stdout)
544 545
}

546
fn stderr_isatty() -> bool {
547
    atty::is(atty::Stream::Stderr)
548 549
}

550
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
M
Mark Rousskov 已提交
551
    let normalised =
552
        if code.starts_with('E') { code.to_string() } else { format!("E{0:0>4}", code) };
553 554
    match registry.try_find_description(&normalised) {
        Ok(Some(description)) => {
555
            let mut is_in_code_block = false;
556
            let mut text = String::new();
557
            // Slice off the leading newline and print.
558
            for line in description.lines() {
M
Mark Rousskov 已提交
559 560
                let indent_level =
                    line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len());
561 562 563
                let dedented_line = &line[indent_level..];
                if dedented_line.starts_with("```") {
                    is_in_code_block = !is_in_code_block;
564
                    text.push_str(&line[..(indent_level + 3)]);
565 566
                } else if is_in_code_block && dedented_line.starts_with("# ") {
                    continue;
567
                } else {
568
                    text.push_str(line);
569
                }
570
                text.push('\n');
571
            }
C
Cengiz Can 已提交
572 573 574 575 576
            if stdout_isatty() {
                show_content_with_pager(&text);
            } else {
                print!("{}", text);
            }
577
        }
578
        Ok(None) => {
579 580
            early_error(output, &format!("no extended information for {}", code));
        }
581 582 583
        Err(InvalidErrorCode) => {
            early_error(output, &format!("{} is not a valid error code", code));
        }
584 585 586
    }
}

587
fn show_content_with_pager(content: &str) {
M
Mark Rousskov 已提交
588 589
    let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
        if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
590 591 592 593 594 595
    });

    let mut fallback_to_println = false;

    match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
        Ok(mut pager) => {
596
            if let Some(pipe) = pager.stdin.as_mut() {
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
                if pipe.write_all(content.as_bytes()).is_err() {
                    fallback_to_println = true;
                }
            }

            if pager.wait().is_err() {
                fallback_to_println = true;
            }
        }
        Err(_) => {
            fallback_to_println = true;
        }
    }

    // If pager fails for whatever reason, we should still print the content
    // to standard output
    if fallback_to_println {
C
Cengiz Can 已提交
614
        print!("{}", content);
615 616 617
    }
}

618
impl RustcDefaultCalls {
V
Victor Ding 已提交
619 620 621 622
    fn process_rlink(sess: &Session, compiler: &interface::Compiler) -> Result<(), ErrorReported> {
        if let Input::File(file) = compiler.input() {
            // FIXME: #![crate_type] and #![crate_name] support not implemented yet
            let attrs = vec![];
623
            sess.init_crate_types(collect_crate_types(sess, &attrs));
V
Victor Ding 已提交
624 625 626 627 628 629 630
            let outputs = compiler.build_output_filenames(&sess, &attrs);
            let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
                sess.fatal(&format!("failed to read rlink file: {}", err));
            });
            let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| {
                sess.fatal(&format!("failed to decode rlink: {}", err));
            });
B
bjorn3 已提交
631
            compiler.codegen_backend().link(&sess, codegen_results, &outputs)
V
Victor Ding 已提交
632
        } else {
633
            sess.fatal("rlink must be a file")
V
Victor Ding 已提交
634 635 636 637 638 639 640 641 642 643 644 645 646
        }
    }

    pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
        if sess.opts.debugging_opts.link_only {
            let result = RustcDefaultCalls::process_rlink(sess, compiler);
            abort_on_err(result, sess);
            Compilation::Stop
        } else {
            Compilation::Continue
        }
    }

M
Mark Rousskov 已提交
647 648 649 650 651 652
    pub fn list_metadata(
        sess: &Session,
        metadata_loader: &dyn MetadataLoader,
        matches: &getopts::Matches,
        input: &Input,
    ) -> Compilation {
653
        let r = matches.opt_strs("Z");
L
ljedrz 已提交
654
        if r.iter().any(|s| *s == "ls") {
M
Matthias Krüger 已提交
655 656
            match *input {
                Input::File(ref ifile) => {
657
                    let path = &(*ifile);
A
Alex Crichton 已提交
658
                    let mut v = Vec::new();
659
                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
M
Mark Rousskov 已提交
660
                        .unwrap();
A
Alex Crichton 已提交
661
                    println!("{}", String::from_utf8(v).unwrap());
662
                }
M
Matthias Krüger 已提交
663
                Input::Str { .. } => {
664
                    early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
665 666
                }
            }
N
Nick Cameron 已提交
667
            return Compilation::Stop;
668 669
        }

670
        Compilation::Continue
671 672
    }

M
Mark Rousskov 已提交
673 674 675 676 677 678 679
    fn print_crate_info(
        codegen_backend: &dyn CodegenBackend,
        sess: &Session,
        input: Option<&Input>,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
680
        use rustc_session::config::PrintRequest::*;
K
Kornel 已提交
681 682
        // PrintRequest::NativeStaticLibs is special - printed during linking
        // (empty iterator returns true)
683
        if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
N
Nick Cameron 已提交
684
            return Compilation::Continue;
685 686
        }

J
Jonas Schievink 已提交
687 688 689 690 691 692 693 694 695 696 697 698 699
        let attrs = match input {
            None => None,
            Some(input) => {
                let result = parse_crate_attrs(sess, input);
                match result {
                    Ok(attrs) => Some(attrs),
                    Err(mut parse_error) => {
                        parse_error.emit();
                        return Compilation::Stop;
                    }
                }
            }
        };
700 701
        for req in &sess.opts.prints {
            match *req {
702
                TargetList => {
703 704
                    let mut targets =
                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
J
Joshua Nelson 已提交
705
                    targets.sort_unstable();
706
                    println!("{}", targets.join("\n"));
M
Mark Rousskov 已提交
707
                }
N
Nicholas Nethercote 已提交
708
                Sysroot => println!("{}", sess.sysroot.display()),
709 710 711 712
                TargetLibdir => println!(
                    "{}",
                    sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display()
                ),
713
                TargetSpec => println!("{}", sess.target.to_json().pretty()),
714
                FileNames | CrateName => {
M
Mark Rousskov 已提交
715 716 717
                    let input = input.unwrap_or_else(|| {
                        early_error(ErrorOutputType::default(), "no input file provided")
                    });
718
                    let attrs = attrs.as_ref().unwrap();
719
                    let t_outputs = rustc_interface::util::build_output_filenames(
M
Mark Rousskov 已提交
720
                        input, odir, ofile, attrs, sess,
721
                    );
722
                    let id = rustc_session::output::find_crate_name(sess, attrs, input);
723 724
                    if *req == PrintRequest::CrateName {
                        println!("{}", id);
J
Jose Narvaez 已提交
725
                        continue;
726
                    }
V
Victor Ding 已提交
727
                    let crate_types = collect_crate_types(sess, attrs);
728
                    for &style in &crate_types {
729 730
                        let fname =
                            rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
731
                        println!("{}", fname.file_name().unwrap().to_string_lossy());
732 733
                    }
                }
734
                Cfg => {
M
Mark Rousskov 已提交
735 736 737 738
                    let mut cfgs = sess
                        .parse_sess
                        .config
                        .iter()
739
                        .filter_map(|&(name, value)| {
M
Mark Rousskov 已提交
740 741 742 743 744 745 746 747
                            // Note that crt-static is a specially recognized cfg
                            // directive that's printed out here as part of
                            // rust-lang/rust#37406, but in general the
                            // `target_feature` cfg is gated under
                            // rust-lang/rust#29717. For now this is just
                            // specifically allowing the crt-static cfg and that's
                            // it, this is intended to get into Cargo and then go
                            // through to build scripts.
748
                            if (name != sym::target_feature || value != Some(sym::crt_dash_static))
749
                                && !sess.is_nightly_build()
M
Mark Rousskov 已提交
750 751 752 753 754 755 756 757 758 759 760 761
                                && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
                            {
                                return None;
                            }

                            if let Some(value) = value {
                                Some(format!("{}=\"{}\"", name, value))
                            } else {
                                Some(name.to_string())
                            }
                        })
                        .collect::<Vec<String>>();
J
Jeffrey Seyfried 已提交
762 763 764 765

                    cfgs.sort();
                    for cfg in cfgs {
                        println!("{}", cfg);
766 767
                    }
                }
768
                RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
I
Irina Popa 已提交
769
                    codegen_backend.print(*req, sess);
770
                }
771 772
                // Any output here interferes with Cargo's parsing of other printed output
                PrintRequest::NativeStaticLibs => {}
773 774
            }
        }
775
        Compilation::Stop
B
Brian Anderson 已提交
776 777 778
    }
}

779
/// Prints version information
780 781
pub fn version(binary: &str, matches: &getopts::Matches) {
    let verbose = matches.opt_present("verbose");
782

783
    println!("{} {}", binary, util::version_str().unwrap_or("unknown version"));
784

785
    if verbose {
J
Jose Narvaez 已提交
786 787 788
        fn unw(x: Option<&str>) -> &str {
            x.unwrap_or("unknown")
        }
789
        println!("binary: {}", binary);
790 791
        println!("commit-hash: {}", unw(util::commit_hash_str()));
        println!("commit-date: {}", unw(util::commit_date_str()));
792
        println!("host: {}", config::host_triple());
793
        println!("release: {}", unw(util::release_str()));
794
        if cfg!(feature = "llvm") {
795 796
            get_builtin_codegen_backend("llvm")().print_version();
        }
797
    }
N
Nick Cameron 已提交
798 799
}

800
fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
M
Mark Rousskov 已提交
801
    let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
802 803 804 805
    let mut options = getopts::Options::new();
    for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
        (option.apply)(&mut options);
    }
L
ljedrz 已提交
806
    let message = "Usage: rustc [OPTIONS] INPUT";
807
    let nightly_help = if nightly_build {
808
        "\n    -Z help             Print unstable compiler options"
809 810 811 812
    } else {
        ""
    };
    let verbose_help = if verbose {
813 814 815 816
        ""
    } else {
        "\n    --help -v           Print the full set of options rustc accepts"
    };
817
    let at_path = if verbose {
818 819 820 821
        "    @path               Read newline separated options from `path`\n"
    } else {
        ""
    };
M
Mark Rousskov 已提交
822 823
    println!(
        "{options}{at_path}\nAdditional help:
N
Nick Cameron 已提交
824
    -C help             Print codegen options
J
Jose Narvaez 已提交
825
    -W help             \
826
              Print 'lint' options and default settings{nightly}{verbose}\n",
M
Mark Rousskov 已提交
827 828 829 830 831
        options = options.usage(message),
        at_path = at_path,
        nightly = nightly_help,
        verbose = verbose_help
    );
N
Nick Cameron 已提交
832 833
}

P
Phlosioneer 已提交
834
fn print_wall_help() {
M
Mark Rousskov 已提交
835 836
    println!(
        "
837 838 839
The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
default. Use `rustc -W help` to see all available lints. It's more common to put
warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
P
Phlosioneer 已提交
840
the command line flag directly.
M
Mark Rousskov 已提交
841 842
"
    );
P
Phlosioneer 已提交
843 844
}

845
fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
M
Mark Rousskov 已提交
846 847
    println!(
        "
N
Nick Cameron 已提交
848 849
Available lint options:
    -W <foo>           Warn about <foo>
J
Jose Narvaez 已提交
850 851
    -A <foo>           \
              Allow <foo>
N
Nick Cameron 已提交
852
    -D <foo>           Deny <foo>
J
Jose Narvaez 已提交
853
    -F <foo>           Forbid <foo> \
854
              (deny <foo> and all attempts to override)
855

M
Mark Rousskov 已提交
856 857
"
    );
N
Nick Cameron 已提交
858

859
    fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> {
V
varkor 已提交
860
        // The sort doesn't case-fold but it's doubtful we care.
861
        lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess.edition()), x.name));
862 863 864
        lints
    }

M
Mark Rousskov 已提交
865
    fn sort_lint_groups(
866 867
        lints: Vec<(&'static str, Vec<LintId>, bool)>,
    ) -> Vec<(&'static str, Vec<LintId>)> {
868
        let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
S
Shotaro Yamada 已提交
869
        lints.sort_by_key(|l| l.0);
870 871 872
        lints
    }

M
Mark Rousskov 已提交
873 874
    let (plugin, builtin): (Vec<_>, _) =
        lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_plugin);
875 876
    let plugin = sort_lints(sess, plugin);
    let builtin = sort_lints(sess, builtin);
877

M
Mark Rousskov 已提交
878 879
    let (plugin_groups, builtin_groups): (Vec<_>, _) =
        lint_store.get_lint_groups().iter().cloned().partition(|&(.., p)| p);
880 881 882
    let plugin_groups = sort_lint_groups(plugin_groups);
    let builtin_groups = sort_lint_groups(builtin_groups);

M
Mark Rousskov 已提交
883 884
    let max_name_len =
        plugin.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0);
885
    let padded = |x: &str| {
S
Shotaro Yamada 已提交
886
        let mut s = " ".repeat(max_name_len - x.chars().count());
887 888
        s.push_str(x);
        s
889
    };
N
Nick Cameron 已提交
890

891
    println!("Lint checks provided by rustc:\n");
A
Alex Crichton 已提交
892 893
    println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
    println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
894

895
    let print_lints = |lints: Vec<&Lint>| {
896
        for lint in lints {
897
            let name = lint.name_lower().replace("_", "-");
898 899 900 901 902 903
            println!(
                "    {}  {:7.7}  {}",
                padded(&name),
                lint.default_level(sess.edition()).as_str(),
                lint.desc
            );
904 905 906 907 908 909
        }
        println!("\n");
    };

    print_lints(builtin);

M
Mark Rousskov 已提交
910 911 912 913 914 915 916 917 918
    let max_name_len = max(
        "warnings".len(),
        plugin_groups
            .iter()
            .chain(&builtin_groups)
            .map(|&(s, _)| s.chars().count())
            .max()
            .unwrap_or(0),
    );
919

920
    let padded = |x: &str| {
S
Shotaro Yamada 已提交
921
        let mut s = " ".repeat(max_name_len - x.chars().count());
922 923
        s.push_str(x);
        s
924 925 926 927 928
    };

    println!("Lint groups provided by rustc:\n");
    println!("    {}  {}", padded("name"), "sub-lints");
    println!("    {}  {}", padded("----"), "---------");
929
    println!("    {}  {}", padded("warnings"), "all lints that are set to issue warnings");
930

931
    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
932
        for (name, to) in lints {
933
            let name = name.to_lowercase().replace("_", "-");
M
Mark Rousskov 已提交
934 935 936 937 938
            let desc = to
                .into_iter()
                .map(|x| x.to_string().replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
939
            println!("    {}  {}", padded(&name), desc);
K
Keegan McAllister 已提交
940
        }
941 942 943 944 945 946 947
        println!("\n");
    };

    print_lint_groups(builtin_groups);

    match (loaded_plugins, plugin.len(), plugin_groups.len()) {
        (false, 0, _) | (false, _, 0) => {
948
            println!("Lint tools like Clippy can provide additional lints and lint groups.");
949
        }
V
Vadim Petrochenkov 已提交
950
        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
951 952 953 954 955 956 957 958 959 960
        (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
        (true, l, g) => {
            if l > 0 {
                println!("Lint checks provided by plugins loaded by this crate:\n");
                print_lints(plugin);
            }
            if g > 0 {
                println!("Lint groups provided by plugins loaded by this crate:\n");
                print_lint_groups(plugin_groups);
            }
K
Keegan McAllister 已提交
961 962
        }
    }
N
Nick Cameron 已提交
963 964 965
}

fn describe_debug_flags() {
966
    println!("\nAvailable options:\n");
967
    print_flag_list("-Z", config::DB_OPTIONS);
N
Nick Cameron 已提交
968 969 970 971
}

fn describe_codegen_flags() {
    println!("\nAvailable codegen options:\n");
972 973 974
    print_flag_list("-C", config::CG_OPTIONS);
}

M
Mark Rousskov 已提交
975 976
fn print_flag_list<T>(
    cmdline_opt: &str,
977
    flag_list: &[(&'static str, T, &'static str, &'static str)],
M
Mark Rousskov 已提交
978
) {
979
    let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
980

981
    for &(name, _, _, desc) in flag_list {
M
Mark Rousskov 已提交
982
        println!(
983
            "    {} {:>width$}=val -- {}",
M
Mark Rousskov 已提交
984 985 986
            cmdline_opt,
            name.replace("_", "-"),
            desc,
987
            width = max_len
M
Mark Rousskov 已提交
988
        );
N
Nick Cameron 已提交
989 990 991
    }
}

992
/// Process command line options. Emits messages as appropriate. If compilation
993
/// should continue, returns a getopts::Matches object parsed from args,
A
Alexander Regueiro 已提交
994
/// otherwise returns `None`.
995
///
K
king6cong 已提交
996
/// The compiler's handling of options is a little complicated as it ties into
997 998
/// our stability story. The current intention of each compiler option is to
/// have one of two modes:
999 1000
///
/// 1. An option is stable and can be used everywhere.
1001
/// 2. An option is unstable, and can only be used on nightly.
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
///
/// Like unstable library and language features, however, unstable options have
/// always required a form of "opt in" to indicate that you're using them. This
/// provides the easy ability to scan a code base to check to see if anything
/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
///
/// All options behind `-Z` are considered unstable by default. Other top-level
/// options can also be considered unstable, and they were unlocked through the
/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
/// instability in both cases, though.
///
/// So with all that in mind, the comments below have some more detail about the
/// contortions done here to get things to work out correctly.
1015
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
1016
    // Throw away the first argument, the name of the binary
1017
    let args = &args[1..];
N
Nick Cameron 已提交
1018

1019
    if args.is_empty() {
1020 1021
        // user did not write `-v` nor `-Z unstable-options`, so do not
        // include that extra information.
1022 1023 1024
        let nightly_build =
            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
        usage(false, false, nightly_build);
1025 1026
        return None;
    }
N
Nick Cameron 已提交
1027

1028 1029
    // Parse with *all* options defined in the compiler, we don't worry about
    // option stability here we just want to parse as much as possible.
1030 1031 1032 1033
    let mut options = getopts::Options::new();
    for option in config::rustc_optgroups() {
        (option.apply)(&mut options);
    }
M
Mark Rousskov 已提交
1034 1035 1036
    let matches = options
        .parse(args)
        .unwrap_or_else(|f| early_error(ErrorOutputType::default(), &f.to_string()));
1037

1038 1039 1040 1041 1042 1043 1044 1045 1046
    // For all options we just parsed, we check a few aspects:
    //
    // * If the option is stable, we're all good
    // * If the option wasn't passed, we're all good
    // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
    //   ourselves), then we require the `-Z unstable-options` flag to unlock
    //   this option that was passed.
    // * If we're a nightly compiler, then unstable options are now unlocked, so
    //   we're good to go.
1047
    // * Otherwise, if we're an unstable option then we generate an error
1048
    //   (unstable option being used on stable)
1049
    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
1050

N
Nick Cameron 已提交
1051
    if matches.opt_present("h") || matches.opt_present("help") {
1052
        // Only show unstable options in --help if we accept unstable options.
1053 1054 1055
        let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
        let nightly_build = nightly_options::match_is_nightly_build(&matches);
        usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
N
Nick Cameron 已提交
1056 1057 1058
        return None;
    }

P
Phlosioneer 已提交
1059 1060 1061 1062 1063 1064
    // Handle the special case of -Wall.
    let wall = matches.opt_strs("W");
    if wall.iter().any(|x| *x == "all") {
        print_wall_help();
        return None;
    }
N
Nick Cameron 已提交
1065

1066
    // Don't handle -W help here, because we might first load plugins.
N
Nick Cameron 已提交
1067
    let r = matches.opt_strs("Z");
1068
    if r.iter().any(|x| *x == "help") {
N
Nick Cameron 已提交
1069 1070 1071 1072 1073
        describe_debug_flags();
        return None;
    }

    let cg_flags = matches.opt_strs("C");
1074

1075
    if cg_flags.iter().any(|x| *x == "help") {
N
Nick Cameron 已提交
1076 1077 1078 1079
        describe_codegen_flags();
        return None;
    }

1080
    if cg_flags.iter().any(|x| *x == "no-stack-check") {
M
Mark Rousskov 已提交
1081 1082 1083 1084
        early_warn(
            ErrorOutputType::default(),
            "the --no-stack-check flag is deprecated and does nothing",
        );
1085 1086
    }

L
ljedrz 已提交
1087
    if cg_flags.iter().any(|x| *x == "passes=list") {
1088
        if cfg!(feature = "llvm") {
1089 1090
            get_builtin_codegen_backend("llvm")().print_passes();
        }
N
Nick Cameron 已提交
1091 1092 1093
        return None;
    }

1094
    if matches.opt_present("version") {
1095 1096
        version("rustc", &matches);
        return None;
N
Nick Cameron 已提交
1097 1098 1099 1100 1101
    }

    Some(matches)
}

1102
fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
1103
    match input {
M
Mark Rousskov 已提交
1104 1105 1106 1107 1108 1109
        Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess),
        Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str(
            name.clone(),
            input.clone(),
            &sess.parse_sess,
        ),
1110
    }
N
Nick Cameron 已提交
1111 1112
}

A
Alexander Regueiro 已提交
1113
/// Gets a list of extra command-line flags provided by the user, as strings.
1114 1115 1116 1117 1118
///
/// This function is used during ICEs to show more information useful for
/// debugging, since some ICEs only happens with non-default compiler flags
/// (and the users don't always report them).
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
1119
    let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::<Vec<_>>();
1120

1121 1122 1123 1124 1125 1126
    // Avoid printing help because of empty args. This can suggest the compiler
    // itself is not the program root (consider RLS).
    if args.len() < 2 {
        return None;
    }

1127
    let matches = handle_options(&args)?;
1128 1129 1130 1131 1132 1133 1134
    let mut result = Vec::new();
    let mut excluded_cargo_defaults = false;
    for flag in ICE_REPORT_COMPILER_FLAGS {
        let prefix = if flag.len() == 1 { "-" } else { "--" };

        for content in &matches.opt_strs(flag) {
            // Split always returns the first element
M
Mark Rousskov 已提交
1135
            let name = if let Some(first) = content.split('=').next() { first } else { &content };
1136

M
Mark Rousskov 已提交
1137 1138
            let content =
                if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content };
1139 1140 1141 1142 1143 1144 1145 1146 1147

            if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
                result.push(format!("{}{} {}", prefix, flag, content));
            } else {
                excluded_cargo_defaults = true;
            }
        }
    }

M
Mark Rousskov 已提交
1148
    if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
1149 1150
}

1151
/// Runs a closure and catches unwinds triggered by fatal errors.
N
Nick Cameron 已提交
1152
///
1153
/// The compiler currently unwinds with a special sentinel value to abort
1154 1155 1156
/// compilation on fatal errors. This function catches that sentinel and turns
/// the panic into a `Result` instead.
pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
1157
    catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
1158
        if value.is::<rustc_errors::FatalErrorMarker>() {
1159
            ErrorReported
1160
        } else {
1161 1162 1163 1164
            panic::resume_unwind(value);
        }
    })
}
N
Nick Cameron 已提交
1165

1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
/// that also computes the exit code.
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
    let result = catch_fatal_errors(f).and_then(|result| result);
    match result {
        Ok(()) => EXIT_SUCCESS,
        Err(_) => EXIT_FAILURE,
    }
}

1176 1177
static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
    SyncLazy::new(|| {
1178
        let hook = panic::take_hook();
1179
        panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL)));
1180
        hook
1181
    });
1182

1183 1184 1185 1186 1187 1188 1189
/// Prints the ICE message, including backtrace and query stack.
///
/// The message will point the user at `bug_report_url` to report the ICE.
///
/// When `install_ice_hook` is called, this function will be called as the panic
/// hook.
pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
1190
    // Invoke the default handler, which prints the actual panic message and optionally a backtrace
1191 1192
    (*DEFAULT_HOOK)(info);

J
Jonas Schievink 已提交
1193
    // Separate the output with an empty line
1194 1195
    eprintln!();

1196 1197
    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
1198 1199 1200 1201
        None,
        false,
        false,
        None,
1202
        false,
1203
    ));
1204
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
1205 1206 1207

    // a .span_bug or .bug call has already printed what
    // it wants to print.
1208 1209
    if !info.payload().is::<rustc_errors::ExplicitBug>() {
        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
1210
        handler.emit_diagnostic(&d);
1211
    }
1212

1213 1214
    let mut xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
1215
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
M
Mark Rousskov 已提交
1216 1217
        format!(
            "rustc {} running on {}",
1218
            util::version_str().unwrap_or("unknown_version"),
M
Mark Rousskov 已提交
1219 1220 1221
            config::host_triple()
        )
        .into(),
1222
    ];
1223

1224 1225
    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
        xs.push(format!("compiler flags: {}", flags.join(" ")).into());
1226

1227 1228
        if excluded_cargo_defaults {
            xs.push("some of the compiler flags provided by cargo are hidden".into());
1229
        }
1230 1231 1232
    }

    for note in &xs {
1233
        handler.note_without_error(&note);
1234
    }
1235 1236

    // If backtraces are enabled, also print the query stack
1237
    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
1238

H
hosseind75 已提交
1239 1240
    let num_frames = if backtrace { None } else { Some(2) };

1241
    interface::try_print_query_stack(&handler, num_frames);
1242 1243 1244 1245 1246

    #[cfg(windows)]
    unsafe {
        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
            // Trigger a debugger if we crashed during bootstrap
1247
            winapi::um::debugapi::DebugBreak();
1248 1249
        }
    }
1250 1251
}

1252 1253 1254
/// Installs a panic hook that will print the ICE message on unexpected panics.
///
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
1255
pub fn install_ice_hook() {
1256
    SyncLazy::force(&DEFAULT_HOOK);
N
Nick Cameron 已提交
1257
}
1258

1259
/// This allows tools to enable rust logging without having to magically match rustc's
G
Gurpreet Singh 已提交
1260
/// tracing crate version.
1261
pub fn init_rustc_env_logger() {
1262 1263 1264 1265
    init_env_logger("RUSTC_LOG")
}

/// This allows tools to enable rust logging without having to magically match rustc's
G
Gurpreet Singh 已提交
1266
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
1267 1268
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
1269 1270 1271 1272 1273 1274
    // Don't register a dispatcher if there's no filter to print anything
    match std::env::var(env) {
        Err(_) => return,
        Ok(s) if s.is_empty() => return,
        Ok(_) => {}
    }
1275 1276 1277 1278
    let color_logs = match std::env::var(String::from(env) + "_COLOR") {
        Ok(value) => match value.as_ref() {
            "always" => true,
            "never" => false,
1279
            "auto" => stderr_isatty(),
C
Camelid 已提交
1280 1281 1282 1283 1284 1285 1286
            _ => early_error(
                ErrorOutputType::default(),
                &format!(
                    "invalid log color value '{}': expected one of always, never, or auto",
                    value
                ),
            ),
1287
        },
1288
        Err(std::env::VarError::NotPresent) => stderr_isatty(),
C
Camelid 已提交
1289 1290 1291 1292
        Err(std::env::VarError::NotUnicode(_value)) => early_error(
            ErrorOutputType::default(),
            "non-Unicode log color value: expected one of always, never, or auto",
        ),
1293
    };
1294 1295
    let filter = tracing_subscriber::EnvFilter::from_env(env);
    let layer = tracing_tree::HierarchicalLayer::default()
1296
        .with_writer(io::stderr)
1297
        .with_indent_lines(true)
1298
        .with_ansi(color_logs)
1299 1300 1301 1302 1303
        .with_targets(true)
        .with_wraparound(10)
        .with_verbose_exit(true)
        .with_verbose_entry(true)
        .with_indent_amount(2);
1304 1305
    #[cfg(parallel_compiler)]
    let layer = layer.with_thread_ids(true).with_thread_names(true);
1306 1307 1308 1309

    use tracing_subscriber::layer::SubscriberExt;
    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
    tracing::subscriber::set_global_default(subscriber).unwrap();
1310 1311
}

1312
pub fn main() -> ! {
1313 1314
    let start_time = Instant::now();
    let start_rss = get_resident_set_size();
1315
    init_rustc_env_logger();
1316
    let mut callbacks = TimePassesCallbacks::default();
1317
    install_ice_hook();
1318
    let exit_code = catch_with_exit_code(|| {
M
Mark Rousskov 已提交
1319 1320 1321 1322 1323 1324
        let args = env::args_os()
            .enumerate()
            .map(|(i, arg)| {
                arg.into_string().unwrap_or_else(|arg| {
                    early_error(
                        ErrorOutputType::default(),
C
Camelid 已提交
1325
                        &format!("argument {} is not valid Unicode: {:?}", i, arg),
M
Mark Rousskov 已提交
1326 1327 1328
                    )
                })
            })
B
bjorn3 已提交
1329
            .collect::<Vec<_>>();
1330
        RunCompiler::new(&args, &mut callbacks).run()
1331
    });
1332 1333 1334 1335 1336 1337

    if callbacks.time_passes {
        let end_rss = get_resident_set_size();
        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
    }

1338
    process::exit(exit_code)
1339
}