lib.rs 46.8 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::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 30
use rustc_middle::middle::cstore::MetadataLoader;
use rustc_middle::ty::TyCtxt;
M
Mark Rousskov 已提交
31 32
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
V
Victor Ding 已提交
33
use rustc_serialize::json::{self, ToJson};
34
use rustc_session::config::nightly_options;
D
Dan Aloni 已提交
35
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
L
Luca Barbieri 已提交
36
use rustc_session::getopts;
37 38 39
use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, DiagnosticOutput, Session};
use rustc_session::{early_error, early_warn};
40 41
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
42

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

58
mod args;
M
Mark Rousskov 已提交
59
pub mod pretty;
60

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

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

67 68
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";
69 70 71 72 73 74

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"];
75

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

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

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

impl Callbacks for TimePassesCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
125 126
        // 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 已提交
127 128
        self.time_passes = config.opts.prints.is_empty()
            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
129
        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
130 131 132
    }
}

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

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 179
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,
        )
    }
}
180 181
// 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.
182
fn run_compiler(
183
    at_args: &[String],
184 185
    callbacks: &mut (dyn Callbacks + Send),
    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
M
Mark Rousskov 已提交
186
    emitter: Option<Box<dyn Write + Send>>,
187 188 189
    make_codegen_backend: Option<
        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
    >,
190
) -> interface::Result<()> {
191 192 193 194
    let mut args = Vec::new();
    for arg in at_args {
        match args::arg_expand(arg.clone()) {
            Ok(arg) => args.extend(arg),
M
Mark Rousskov 已提交
195 196 197 198
            Err(err) => early_error(
                ErrorOutputType::default(),
                &format!("Failed to load argument file: {}", err),
            ),
199 200
        }
    }
K
Kazantcev Andrey 已提交
201
    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
202
    let matches = match handle_options(&args) {
203
        Some(matches) => matches,
204
        None => return Ok(()),
205
    };
J
John Kåre Alsaker 已提交
206

207
    let sopts = config::build_session_options(&matches);
208
    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
N
Nick Cameron 已提交
209

210 211 212 213 214
    // 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);

215 216 217 218 219 220 221 222 223 224 225 226 227
    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,
            crate_name: None,
            lint_caps: Default::default(),
228
            register_lints: None,
229
            override_queries: None,
230
            make_codegen_backend: make_codegen_backend.take().unwrap(),
231
            registry: diagnostics_registry(),
232 233 234 235
        };
        callbacks.config(&mut config);
        config
    };
236

237
    if let Some(ref code) = matches.opt_str("explain") {
238
        handle_explain(diagnostics_registry(), code, sopts.error_format);
239 240
        return Ok(());
    }
241 242

    let (odir, ofile) = make_output(&matches);
243
    let (input, input_file_path, input_err) = match make_input(&matches.free) {
244
        Some(v) => v,
M
Mark Rousskov 已提交
245 246 247 248 249 250
        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 {
251
                        let mut lint_store = rustc_lint::new_lint_store(
M
Mark Rousskov 已提交
252 253
                            sopts.debugging_opts.no_interleave_lints,
                            compiler.session().unstable_options(),
254
                        );
255 256 257 258 259 260 261 262
                        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 已提交
263 264 265 266 267 268 269 270 271
                        return;
                    }
                    let should_stop = RustcDefaultCalls::print_crate_info(
                        &***compiler.codegen_backend(),
                        compiler.session(),
                        None,
                        &odir,
                        &ofile,
                    );
N
Nick Cameron 已提交
272

M
Mark Rousskov 已提交
273 274 275 276 277 278
                    if should_stop == Compilation::Stop {
                        return;
                    }
                    early_error(sopts.error_format, "no input filename given")
                });
                return Ok(());
279
            }
M
Mark Rousskov 已提交
280 281 282 283 284 285 286 287 288
            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],
                ),
            ),
        },
289
    };
290

291 292 293
    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).
294 295 296 297
        interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| {
            compiler.session().err(&err.to_string());
        });
        return Err(ErrorReported);
298 299
    }

300 301 302 303 304 305 306 307 308 309 310 311
    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,
        crate_name: None,
        lint_caps: Default::default(),
312
        register_lints: None,
313
        override_queries: None,
314
        make_codegen_backend: make_codegen_backend.unwrap(),
315
        registry: diagnostics_registry(),
316 317 318 319 320 321 322 323 324 325 326 327
    };

    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 已提交
328 329 330 331 332 333 334 335
        )
        .and_then(|| {
            RustcDefaultCalls::list_metadata(
                sess,
                &*compiler.codegen_backend().metadata_loader(),
                &matches,
                compiler.input(),
            )
V
Victor Ding 已提交
336 337
        })
        .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
338 339 340 341 342

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

343
        let linker = compiler.enter(|queries| {
C
Camille GILLOT 已提交
344
            let early_exit = || sess.compile_status().map(|_| None);
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
            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,
366
                        *ppm,
367 368
                        compiler.output_file().as_ref().map(|p| &**p),
                    );
369
                }
J
Joshua Nelson 已提交
370
                trace!("finished pretty-printing");
C
Camille GILLOT 已提交
371
                return early_exit();
372
            }
373

R
Ralf Jung 已提交
374
            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
375
                return early_exit();
376
            }
N
Nick Cameron 已提交
377

M
Mark Rousskov 已提交
378 379 380 381 382
            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();
383
            }
384

385 386
            {
                let (_, lint_store) = &*queries.register_plugins()?.peek();
387

388 389 390
                // 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 已提交
391
                    return early_exit();
392 393 394 395
                }
            }

            queries.expansion()?;
R
Ralf Jung 已提交
396
            if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
397
                return early_exit();
398
            }
399

400 401 402 403 404
            queries.prepare_outputs()?;

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

408
            queries.global_ctxt()?;
409

410
            // Drop AST after creating GlobalCtxt to free memory
411 412 413 414
            {
                let _timer = sess.prof.generic_activity("drop_ast");
                mem::drop(queries.expansion()?.take());
            }
415

M
Mark Rousskov 已提交
416 417
            if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
                return early_exit();
418
            }
419

420 421 422 423 424
            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);

425
                    sess.time("save_analysis", || {
426 427 428 429 430
                        save::process_crate(
                            tcx,
                            &crate_name,
                            &compiler.input(),
                            None,
C
Tidy.  
Camille GILLOT 已提交
431
                            DumpHandler::new(
M
Mark Rousskov 已提交
432 433 434
                                compiler.output_dir().as_ref().map(|p| &**p),
                                &crate_name,
                            ),
435 436
                        )
                    });
437

438 439 440
                    result
                })?;
            }
441

442
            queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
443

R
Ralf Jung 已提交
444
            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
C
Camille GILLOT 已提交
445
                return early_exit();
446
            }
447

448
            queries.ongoing_codegen()?;
449

450 451 452
            if sess.opts.debugging_opts.print_type_sizes {
                sess.code_stats.print_type_sizes();
            }
453

454 455
            let linker = queries.linker()?;
            Ok(Some(linker))
456
        })?;
457

458
        if let Some(linker) = linker {
J
John Kåre Alsaker 已提交
459
            let _timer = sess.timer("link");
460 461 462
            linker.link()?
        }

463 464 465 466 467
        if sess.opts.debugging_opts.perf_stats {
            sess.print_perf_stats();
        }

        if sess.print_fuel_crate.is_some() {
M
Mark Rousskov 已提交
468 469
            eprintln!(
                "Fuel used by {}: {}",
470
                sess.print_fuel_crate.as_ref().unwrap(),
M
Mark Rousskov 已提交
471 472
                sess.print_fuel.load(SeqCst)
            );
473
        }
474

475 476
        Ok(())
    })
477 478
}

479 480 481 482 483
#[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 已提交
484
        assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR);
485 486 487 488 489 490
    }
}

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

491
// Extract output directory and file from matches.
A
Alex Crichton 已提交
492
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
A
Aaron Turon 已提交
493 494
    let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
    let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
495 496
    (odir, ofile)
}
497

498
// Extract input (string or file and optional path) from matches.
499
fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
500
    if free_matches.len() == 1 {
501
        let ifile = &free_matches[0];
502
        if ifile == "-" {
503
            let mut src = String::new();
504
            let err = if io::stdin().read_to_string(&mut src).is_err() {
M
Mark Rousskov 已提交
505 506 507 508
                Some(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "couldn't read from stdin, as it did not contain valid UTF-8",
                ))
509 510 511
            } else {
                None
            };
512
            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
M
Mark Rousskov 已提交
513 514 515 516 517 518
                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");
519 520 521
                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 已提交
522
            Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None, err))
523
        } else {
M
Mark Rousskov 已提交
524
            Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)), None))
525 526 527
        }
    } else {
        None
528
    }
529
}
530

N
Nick Cameron 已提交
531
// Whether to stop or continue compilation.
N
Niko Matsakis 已提交
532
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
N
Nick Cameron 已提交
533 534 535 536 537 538 539 540 541
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 已提交
542
            Compilation::Continue => next(),
N
Nick Cameron 已提交
543 544 545 546
        }
    }
}

547
/// CompilerCalls instance for a regular rustc build.
N
Niko Matsakis 已提交
548
#[derive(Copy, Clone)]
549 550
pub struct RustcDefaultCalls;

C
Cengiz Can 已提交
551 552
// FIXME remove these and use winapi 0.3 instead
// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
553 554 555 556
#[cfg(unix)]
fn stdout_isatty() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
}
C
Cengiz Can 已提交
557

558 559
#[cfg(windows)]
fn stdout_isatty() -> bool {
560 561 562 563
    use winapi::um::consoleapi::GetConsoleMode;
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;

564 565 566 567 568 569 570
    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}

571
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
M
Mark Rousskov 已提交
572
    let normalised =
573
        if code.starts_with('E') { code.to_string() } else { format!("E{0:0>4}", code) };
574 575
    match registry.try_find_description(&normalised) {
        Ok(Some(description)) => {
576
            let mut is_in_code_block = false;
577
            let mut text = String::new();
578
            // Slice off the leading newline and print.
579
            for line in description.lines() {
M
Mark Rousskov 已提交
580 581
                let indent_level =
                    line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len());
582 583 584
                let dedented_line = &line[indent_level..];
                if dedented_line.starts_with("```") {
                    is_in_code_block = !is_in_code_block;
585
                    text.push_str(&line[..(indent_level + 3)]);
586 587
                } else if is_in_code_block && dedented_line.starts_with("# ") {
                    continue;
588
                } else {
589
                    text.push_str(line);
590
                }
591
                text.push('\n');
592
            }
C
Cengiz Can 已提交
593 594 595 596 597
            if stdout_isatty() {
                show_content_with_pager(&text);
            } else {
                print!("{}", text);
            }
598
        }
599
        Ok(None) => {
600 601
            early_error(output, &format!("no extended information for {}", code));
        }
602 603 604
        Err(InvalidErrorCode) => {
            early_error(output, &format!("{} is not a valid error code", code));
        }
605 606 607
    }
}

608
fn show_content_with_pager(content: &String) {
M
Mark Rousskov 已提交
609 610
    let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
        if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
611 612 613 614 615 616
    });

    let mut fallback_to_println = false;

    match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
        Ok(mut pager) => {
617
            if let Some(pipe) = pager.stdin.as_mut() {
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
                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 已提交
635
        print!("{}", content);
636 637 638
    }
}

639
impl RustcDefaultCalls {
V
Victor Ding 已提交
640 641 642 643
    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![];
644
            sess.init_crate_types(collect_crate_types(sess, &attrs));
V
Victor Ding 已提交
645 646 647 648 649 650 651
            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 已提交
652
            compiler.codegen_backend().link(&sess, codegen_results, &outputs)
V
Victor Ding 已提交
653
        } else {
654
            sess.fatal("rlink must be a file")
V
Victor Ding 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667
        }
    }

    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 已提交
668 669 670 671 672 673
    pub fn list_metadata(
        sess: &Session,
        metadata_loader: &dyn MetadataLoader,
        matches: &getopts::Matches,
        input: &Input,
    ) -> Compilation {
674
        let r = matches.opt_strs("Z");
L
ljedrz 已提交
675
        if r.iter().any(|s| *s == "ls") {
M
Matthias Krüger 已提交
676 677
            match *input {
                Input::File(ref ifile) => {
678
                    let path = &(*ifile);
A
Alex Crichton 已提交
679
                    let mut v = Vec::new();
680
                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
M
Mark Rousskov 已提交
681
                        .unwrap();
A
Alex Crichton 已提交
682
                    println!("{}", String::from_utf8(v).unwrap());
683
                }
M
Matthias Krüger 已提交
684
                Input::Str { .. } => {
685
                    early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
686 687
                }
            }
N
Nick Cameron 已提交
688
            return Compilation::Stop;
689 690
        }

691
        Compilation::Continue
692 693
    }

M
Mark Rousskov 已提交
694 695 696 697 698 699 700
    fn print_crate_info(
        codegen_backend: &dyn CodegenBackend,
        sess: &Session,
        input: Option<&Input>,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
701
        use rustc_session::config::PrintRequest::*;
K
Kornel 已提交
702 703
        // PrintRequest::NativeStaticLibs is special - printed during linking
        // (empty iterator returns true)
704
        if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
N
Nick Cameron 已提交
705
            return Compilation::Continue;
706 707
        }

J
Jonas Schievink 已提交
708 709 710 711 712 713 714 715 716 717 718 719 720
        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;
                    }
                }
            }
        };
721 722
        for req in &sess.opts.prints {
            match *req {
723
                TargetList => {
724 725
                    let mut targets =
                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
J
Joshua Nelson 已提交
726
                    targets.sort_unstable();
727
                    println!("{}", targets.join("\n"));
M
Mark Rousskov 已提交
728
                }
N
Nicholas Nethercote 已提交
729
                Sysroot => println!("{}", sess.sysroot.display()),
730 731 732 733
                TargetLibdir => println!(
                    "{}",
                    sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display()
                ),
734
                TargetSpec => println!("{}", sess.target.to_json().pretty()),
735
                FileNames | CrateName => {
M
Mark Rousskov 已提交
736 737 738
                    let input = input.unwrap_or_else(|| {
                        early_error(ErrorOutputType::default(), "no input file provided")
                    });
739
                    let attrs = attrs.as_ref().unwrap();
740
                    let t_outputs = rustc_interface::util::build_output_filenames(
M
Mark Rousskov 已提交
741
                        input, odir, ofile, attrs, sess,
742
                    );
743
                    let id = rustc_session::output::find_crate_name(sess, attrs, input);
744 745
                    if *req == PrintRequest::CrateName {
                        println!("{}", id);
J
Jose Narvaez 已提交
746
                        continue;
747
                    }
V
Victor Ding 已提交
748
                    let crate_types = collect_crate_types(sess, attrs);
749
                    for &style in &crate_types {
750 751
                        let fname =
                            rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
752
                        println!("{}", fname.file_name().unwrap().to_string_lossy());
753 754
                    }
                }
755
                Cfg => {
M
Mark Rousskov 已提交
756 757 758 759
                    let mut cfgs = sess
                        .parse_sess
                        .config
                        .iter()
760
                        .filter_map(|&(name, value)| {
M
Mark Rousskov 已提交
761 762 763 764 765 766 767 768
                            // 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.
769
                            if (name != sym::target_feature || value != Some(sym::crt_dash_static))
770
                                && !sess.is_nightly_build()
M
Mark Rousskov 已提交
771 772 773 774 775 776 777 778 779 780 781 782
                                && 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 已提交
783 784 785 786

                    cfgs.sort();
                    for cfg in cfgs {
                        println!("{}", cfg);
787 788
                    }
                }
789
                RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
I
Irina Popa 已提交
790
                    codegen_backend.print(*req, sess);
791
                }
792 793
                // Any output here interferes with Cargo's parsing of other printed output
                PrintRequest::NativeStaticLibs => {}
794 795
            }
        }
796
        Compilation::Stop
B
Brian Anderson 已提交
797 798 799
    }
}

800
/// Prints version information
801 802
pub fn version(binary: &str, matches: &getopts::Matches) {
    let verbose = matches.opt_present("verbose");
803

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

806
    if verbose {
J
Jose Narvaez 已提交
807 808 809
        fn unw(x: Option<&str>) -> &str {
            x.unwrap_or("unknown")
        }
810
        println!("binary: {}", binary);
811 812
        println!("commit-hash: {}", unw(util::commit_hash_str()));
        println!("commit-date: {}", unw(util::commit_date_str()));
813
        println!("host: {}", config::host_triple());
814 815 816 817
        println!("release: {}", unw(util::release_str()));
        if cfg!(llvm) {
            get_builtin_codegen_backend("llvm")().print_version();
        }
818
    }
N
Nick Cameron 已提交
819 820
}

821
fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
M
Mark Rousskov 已提交
822
    let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
823 824 825 826
    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 已提交
827
    let message = "Usage: rustc [OPTIONS] INPUT";
828
    let nightly_help = if nightly_build {
829
        "\n    -Z help             Print unstable compiler options"
830 831 832 833
    } else {
        ""
    };
    let verbose_help = if verbose {
834 835 836 837
        ""
    } else {
        "\n    --help -v           Print the full set of options rustc accepts"
    };
838
    let at_path = if verbose && nightly_build {
839 840 841 842
        "    @path               Read newline separated options from `path`\n"
    } else {
        ""
    };
M
Mark Rousskov 已提交
843 844
    println!(
        "{options}{at_path}\nAdditional help:
N
Nick Cameron 已提交
845
    -C help             Print codegen options
J
Jose Narvaez 已提交
846
    -W help             \
847
              Print 'lint' options and default settings{nightly}{verbose}\n",
M
Mark Rousskov 已提交
848 849 850 851 852
        options = options.usage(message),
        at_path = at_path,
        nightly = nightly_help,
        verbose = verbose_help
    );
N
Nick Cameron 已提交
853 854
}

P
Phlosioneer 已提交
855
fn print_wall_help() {
M
Mark Rousskov 已提交
856 857
    println!(
        "
858 859 860
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 已提交
861
the command line flag directly.
M
Mark Rousskov 已提交
862 863
"
    );
P
Phlosioneer 已提交
864 865
}

866
fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
M
Mark Rousskov 已提交
867 868
    println!(
        "
N
Nick Cameron 已提交
869 870
Available lint options:
    -W <foo>           Warn about <foo>
J
Jose Narvaez 已提交
871 872
    -A <foo>           \
              Allow <foo>
N
Nick Cameron 已提交
873
    -D <foo>           Deny <foo>
J
Jose Narvaez 已提交
874
    -F <foo>           Forbid <foo> \
875
              (deny <foo> and all attempts to override)
876

M
Mark Rousskov 已提交
877 878
"
    );
N
Nick Cameron 已提交
879

880
    fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> {
V
varkor 已提交
881
        // The sort doesn't case-fold but it's doubtful we care.
882
        lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess.edition()), x.name));
883 884 885
        lints
    }

M
Mark Rousskov 已提交
886
    fn sort_lint_groups(
887 888
        lints: Vec<(&'static str, Vec<LintId>, bool)>,
    ) -> Vec<(&'static str, Vec<LintId>)> {
889
        let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
S
Shotaro Yamada 已提交
890
        lints.sort_by_key(|l| l.0);
891 892 893
        lints
    }

M
Mark Rousskov 已提交
894 895
    let (plugin, builtin): (Vec<_>, _) =
        lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_plugin);
896 897
    let plugin = sort_lints(sess, plugin);
    let builtin = sort_lints(sess, builtin);
898

M
Mark Rousskov 已提交
899 900
    let (plugin_groups, builtin_groups): (Vec<_>, _) =
        lint_store.get_lint_groups().iter().cloned().partition(|&(.., p)| p);
901 902 903
    let plugin_groups = sort_lint_groups(plugin_groups);
    let builtin_groups = sort_lint_groups(builtin_groups);

M
Mark Rousskov 已提交
904 905
    let max_name_len =
        plugin.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0);
906
    let padded = |x: &str| {
S
Shotaro Yamada 已提交
907
        let mut s = " ".repeat(max_name_len - x.chars().count());
908 909
        s.push_str(x);
        s
910
    };
N
Nick Cameron 已提交
911

912
    println!("Lint checks provided by rustc:\n");
A
Alex Crichton 已提交
913 914
    println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
    println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
915

916
    let print_lints = |lints: Vec<&Lint>| {
917
        for lint in lints {
918
            let name = lint.name_lower().replace("_", "-");
M
Mark Rousskov 已提交
919
            println!("    {}  {:7.7}  {}", padded(&name), lint.default_level.as_str(), lint.desc);
920 921 922 923 924 925
        }
        println!("\n");
    };

    print_lints(builtin);

M
Mark Rousskov 已提交
926 927 928 929 930 931 932 933 934
    let max_name_len = max(
        "warnings".len(),
        plugin_groups
            .iter()
            .chain(&builtin_groups)
            .map(|&(s, _)| s.chars().count())
            .max()
            .unwrap_or(0),
    );
935

936
    let padded = |x: &str| {
S
Shotaro Yamada 已提交
937
        let mut s = " ".repeat(max_name_len - x.chars().count());
938 939
        s.push_str(x);
        s
940 941 942 943 944
    };

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

947
    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
948
        for (name, to) in lints {
949
            let name = name.to_lowercase().replace("_", "-");
M
Mark Rousskov 已提交
950 951 952 953 954
            let desc = to
                .into_iter()
                .map(|x| x.to_string().replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
955
            println!("    {}  {}", padded(&name), desc);
K
Keegan McAllister 已提交
956
        }
957 958 959 960 961 962 963
        println!("\n");
    };

    print_lint_groups(builtin_groups);

    match (loaded_plugins, plugin.len(), plugin_groups.len()) {
        (false, 0, _) | (false, _, 0) => {
964
            println!("Compiler plugins can provide additional lints and lint groups.");
965
        }
V
Vadim Petrochenkov 已提交
966
        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
967 968 969 970 971 972 973 974 975 976
        (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 已提交
977 978
        }
    }
N
Nick Cameron 已提交
979 980 981
}

fn describe_debug_flags() {
982
    println!("\nAvailable options:\n");
983
    print_flag_list("-Z", config::DB_OPTIONS);
N
Nick Cameron 已提交
984 985 986 987
}

fn describe_codegen_flags() {
    println!("\nAvailable codegen options:\n");
988 989 990
    print_flag_list("-C", config::CG_OPTIONS);
}

M
Mark Rousskov 已提交
991 992
fn print_flag_list<T>(
    cmdline_opt: &str,
993
    flag_list: &[(&'static str, T, &'static str, &'static str)],
M
Mark Rousskov 已提交
994
) {
995
    let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
996

997
    for &(name, _, _, desc) in flag_list {
M
Mark Rousskov 已提交
998
        println!(
999
            "    {} {:>width$}=val -- {}",
M
Mark Rousskov 已提交
1000 1001 1002
            cmdline_opt,
            name.replace("_", "-"),
            desc,
1003
            width = max_len
M
Mark Rousskov 已提交
1004
        );
N
Nick Cameron 已提交
1005 1006 1007
    }
}

1008
/// Process command line options. Emits messages as appropriate. If compilation
1009
/// should continue, returns a getopts::Matches object parsed from args,
A
Alexander Regueiro 已提交
1010
/// otherwise returns `None`.
1011
///
K
king6cong 已提交
1012
/// The compiler's handling of options is a little complicated as it ties into
1013 1014
/// our stability story. The current intention of each compiler option is to
/// have one of two modes:
1015 1016
///
/// 1. An option is stable and can be used everywhere.
1017
/// 2. An option is unstable, and can only be used on nightly.
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
///
/// 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.
1031
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
1032
    // Throw away the first argument, the name of the binary
1033
    let args = &args[1..];
N
Nick Cameron 已提交
1034

1035
    if args.is_empty() {
1036 1037
        // user did not write `-v` nor `-Z unstable-options`, so do not
        // include that extra information.
1038 1039 1040
        let nightly_build =
            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
        usage(false, false, nightly_build);
1041 1042
        return None;
    }
N
Nick Cameron 已提交
1043

1044 1045
    // 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.
1046 1047 1048 1049
    let mut options = getopts::Options::new();
    for option in config::rustc_optgroups() {
        (option.apply)(&mut options);
    }
M
Mark Rousskov 已提交
1050 1051 1052
    let matches = options
        .parse(args)
        .unwrap_or_else(|f| early_error(ErrorOutputType::default(), &f.to_string()));
1053

1054 1055 1056 1057 1058 1059 1060 1061 1062
    // 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.
1063
    // * Otherwise, if we're an unstable option then we generate an error
1064
    //   (unstable option being used on stable)
1065
    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
1066

N
Nick Cameron 已提交
1067
    if matches.opt_present("h") || matches.opt_present("help") {
1068
        // Only show unstable options in --help if we accept unstable options.
1069 1070 1071
        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 已提交
1072 1073 1074
        return None;
    }

P
Phlosioneer 已提交
1075 1076 1077 1078 1079 1080
    // 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 已提交
1081

1082
    // Don't handle -W help here, because we might first load plugins.
N
Nick Cameron 已提交
1083
    let r = matches.opt_strs("Z");
1084
    if r.iter().any(|x| *x == "help") {
N
Nick Cameron 已提交
1085 1086 1087 1088 1089
        describe_debug_flags();
        return None;
    }

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

1091
    if cg_flags.iter().any(|x| *x == "help") {
N
Nick Cameron 已提交
1092 1093 1094 1095
        describe_codegen_flags();
        return None;
    }

1096
    if cg_flags.iter().any(|x| *x == "no-stack-check") {
M
Mark Rousskov 已提交
1097 1098 1099 1100
        early_warn(
            ErrorOutputType::default(),
            "the --no-stack-check flag is deprecated and does nothing",
        );
1101 1102
    }

L
ljedrz 已提交
1103
    if cg_flags.iter().any(|x| *x == "passes=list") {
1104 1105 1106
        if cfg!(llvm) {
            get_builtin_codegen_backend("llvm")().print_passes();
        }
N
Nick Cameron 已提交
1107 1108 1109
        return None;
    }

1110
    if matches.opt_present("version") {
1111 1112
        version("rustc", &matches);
        return None;
N
Nick Cameron 已提交
1113 1114 1115 1116 1117
    }

    Some(matches)
}

1118
fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
1119
    match input {
M
Mark Rousskov 已提交
1120 1121 1122 1123 1124 1125
        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,
        ),
1126
    }
N
Nick Cameron 已提交
1127 1128
}

A
Alexander Regueiro 已提交
1129
/// Gets a list of extra command-line flags provided by the user, as strings.
1130 1131 1132 1133 1134
///
/// 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)> {
1135
    let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::<Vec<_>>();
1136

1137 1138 1139 1140 1141 1142
    // 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;
    }

1143
    let matches = handle_options(&args)?;
1144 1145 1146 1147 1148 1149 1150
    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 已提交
1151
            let name = if let Some(first) = content.split('=').next() { first } else { &content };
1152

M
Mark Rousskov 已提交
1153 1154
            let content =
                if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content };
1155 1156 1157 1158 1159 1160 1161 1162 1163

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

M
Mark Rousskov 已提交
1164
    if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
1165 1166
}

1167
/// Runs a closure and catches unwinds triggered by fatal errors.
N
Nick Cameron 已提交
1168
///
1169
/// The compiler currently unwinds with a special sentinel value to abort
1170 1171 1172
/// 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> {
1173
    catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
1174
        if value.is::<rustc_errors::FatalErrorMarker>() {
1175
            ErrorReported
1176
        } else {
1177 1178 1179 1180
            panic::resume_unwind(value);
        }
    })
}
N
Nick Cameron 已提交
1181

1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
/// 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,
    }
}

1192 1193
static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
    SyncLazy::new(|| {
1194
        let hook = panic::take_hook();
1195
        panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL)));
1196
        hook
1197
    });
1198

1199 1200 1201 1202 1203 1204 1205
/// 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) {
1206
    // Invoke the default handler, which prints the actual panic message and optionally a backtrace
1207 1208
    (*DEFAULT_HOOK)(info);

J
Jonas Schievink 已提交
1209
    // Separate the output with an empty line
1210 1211
    eprintln!();

1212 1213
    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
1214 1215 1216 1217
        None,
        false,
        false,
        None,
1218
        false,
1219
    ));
1220
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
1221 1222 1223

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

1229 1230
    let mut xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
1231
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
M
Mark Rousskov 已提交
1232 1233
        format!(
            "rustc {} running on {}",
1234
            util::version_str().unwrap_or("unknown_version"),
M
Mark Rousskov 已提交
1235 1236 1237
            config::host_triple()
        )
        .into(),
1238
    ];
1239

1240 1241
    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
        xs.push(format!("compiler flags: {}", flags.join(" ")).into());
1242

1243 1244
        if excluded_cargo_defaults {
            xs.push("some of the compiler flags provided by cargo are hidden".into());
1245
        }
1246 1247 1248
    }

    for note in &xs {
1249
        handler.note_without_error(&note);
1250
    }
1251 1252 1253 1254

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

H
hosseind75 已提交
1255 1256 1257
    let num_frames = if backtrace { None } else { Some(2) };

    TyCtxt::try_print_query_stack(&handler, num_frames);
1258 1259 1260 1261 1262

    #[cfg(windows)]
    unsafe {
        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
            // Trigger a debugger if we crashed during bootstrap
1263
            winapi::um::debugapi::DebugBreak();
1264 1265
        }
    }
1266 1267
}

1268 1269 1270
/// 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.
1271
pub fn install_ice_hook() {
1272
    SyncLazy::force(&DEFAULT_HOOK);
N
Nick Cameron 已提交
1273
}
1274

1275
/// This allows tools to enable rust logging without having to magically match rustc's
G
Gurpreet Singh 已提交
1276
/// tracing crate version.
1277
pub fn init_rustc_env_logger() {
1278 1279 1280 1281
    init_env_logger("RUSTC_LOG")
}

/// This allows tools to enable rust logging without having to magically match rustc's
G
Gurpreet Singh 已提交
1282
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
1283 1284
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
1285 1286 1287 1288 1289 1290
    // 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(_) => {}
    }
1291 1292
    let filter = tracing_subscriber::EnvFilter::from_env(env);
    let layer = tracing_tree::HierarchicalLayer::default()
1293
        .with_writer(io::stderr)
1294 1295 1296 1297 1298 1299 1300
        .with_indent_lines(true)
        .with_ansi(true)
        .with_targets(true)
        .with_wraparound(10)
        .with_verbose_exit(true)
        .with_verbose_entry(true)
        .with_indent_amount(2);
1301 1302
    #[cfg(parallel_compiler)]
    let layer = layer.with_thread_ids(true).with_thread_names(true);
1303 1304 1305 1306

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

1309
pub fn main() -> ! {
1310
    let start = Instant::now();
1311
    init_rustc_env_logger();
1312
    let mut callbacks = TimePassesCallbacks::default();
1313
    install_ice_hook();
1314
    let exit_code = catch_with_exit_code(|| {
M
Mark Rousskov 已提交
1315 1316 1317 1318 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(),
                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
                    )
                })
            })
B
bjorn3 已提交
1325
            .collect::<Vec<_>>();
1326
        RunCompiler::new(&args, &mut callbacks).run()
1327
    });
1328 1329
    // The extra `\t` is necessary to align this label with the others.
    print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
1330
    process::exit(exit_code)
1331
}