rustc: distinguish compilation failure from ICE
This commit changes the exit status of rustc to 1 in the presence of compilation errors. In the event of an unexpected panic (ICE) the standard panic error exit status of 101 remains. A run-make test is added to ensure that the exit code does not regress, and compiletest is updated to check for an exit status of 1 or 101, depending on the mode and suite. This is a breaking change for custom drivers. Fixes #51971.
This commit is contained in:
parent
4f3c7a472b
commit
8f4ccac5e2
9 changed files with 110 additions and 25 deletions
|
@ -94,7 +94,9 @@ use std::cmp::max;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::error::Error;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::fmt::{self, Display};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -146,6 +148,12 @@ pub mod target_features {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exit status code used for successful compilation and help output.
|
||||||
|
pub const EXIT_SUCCESS: isize = 0;
|
||||||
|
|
||||||
|
/// Exit status code used for compilation failures and invalid flags.
|
||||||
|
pub const EXIT_FAILURE: isize = 1;
|
||||||
|
|
||||||
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
|
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
|
||||||
md#bug-reports";
|
md#bug-reports";
|
||||||
|
|
||||||
|
@ -178,7 +186,7 @@ pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) ->
|
||||||
pub fn run<F>(run_compiler: F) -> isize
|
pub fn run<F>(run_compiler: F) -> isize
|
||||||
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
|
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
|
||||||
{
|
{
|
||||||
monitor(move || {
|
let result = monitor(move || {
|
||||||
let (result, session) = run_compiler();
|
let (result, session) = run_compiler();
|
||||||
if let Err(CompileIncomplete::Errored(_)) = result {
|
if let Err(CompileIncomplete::Errored(_)) = result {
|
||||||
match session {
|
match session {
|
||||||
|
@ -201,7 +209,11 @@ pub fn run<F>(run_compiler: F) -> isize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
0
|
|
||||||
|
match result {
|
||||||
|
Ok(()) => EXIT_SUCCESS,
|
||||||
|
Err(_) => EXIT_FAILURE,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
|
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
|
||||||
|
@ -1625,20 +1637,30 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompilationFailure;
|
||||||
|
|
||||||
|
impl Error for CompilationFailure {}
|
||||||
|
|
||||||
|
impl Display for CompilationFailure {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "compilation had errors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a procedure which will detect panics in the compiler and print nicer
|
/// Run a procedure which will detect panics in the compiler and print nicer
|
||||||
/// error messages rather than just failing the test.
|
/// error messages rather than just failing the test.
|
||||||
///
|
///
|
||||||
/// The diagnostic emitter yielded to the procedure should be used for reporting
|
/// The diagnostic emitter yielded to the procedure should be used for reporting
|
||||||
/// errors of the compiler.
|
/// errors of the compiler.
|
||||||
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
|
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
|
||||||
let result = in_rustc_thread(move || {
|
in_rustc_thread(move || {
|
||||||
f()
|
f()
|
||||||
});
|
}).map_err(|value| {
|
||||||
|
if value.is::<errors::FatalErrorMarker>() {
|
||||||
if let Err(value) = result {
|
CompilationFailure
|
||||||
|
} else {
|
||||||
// Thread panicked without emitting a fatal diagnostic
|
// Thread panicked without emitting a fatal diagnostic
|
||||||
if !value.is::<errors::FatalErrorMarker>() {
|
|
||||||
// Emit a newline
|
|
||||||
eprintln!("");
|
eprintln!("");
|
||||||
|
|
||||||
let emitter =
|
let emitter =
|
||||||
|
@ -1677,10 +1699,10 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
|
||||||
¬e,
|
¬e,
|
||||||
errors::Level::Note);
|
errors::Level::Note);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
|
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diagnostics_registry() -> errors::registry::Registry {
|
pub fn diagnostics_registry() -> errors::registry::Registry {
|
||||||
|
|
|
@ -57,6 +57,7 @@ use errors::ColorConfig;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::panic;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
@ -115,7 +116,7 @@ pub fn main() {
|
||||||
syntax::with_globals(move || {
|
syntax::with_globals(move || {
|
||||||
get_args().map(|args| main_args(&args)).unwrap_or(1)
|
get_args().map(|args| main_args(&args)).unwrap_or(1)
|
||||||
})
|
})
|
||||||
}).unwrap().join().unwrap_or(101);
|
}).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE);
|
||||||
process::exit(res as i32);
|
process::exit(res as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +668,7 @@ where R: 'static + Send,
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
rustc_driver::monitor(move || syntax::with_globals(move || {
|
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
|
||||||
use rustc::session::config::Input;
|
use rustc::session::config::Input;
|
||||||
|
|
||||||
let (mut krate, renderinfo) =
|
let (mut krate, renderinfo) =
|
||||||
|
@ -771,7 +772,11 @@ where R: 'static + Send,
|
||||||
|
|
||||||
tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap();
|
tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap();
|
||||||
}));
|
}));
|
||||||
rx.recv().unwrap()
|
|
||||||
|
match result {
|
||||||
|
Ok(()) => rx.recv().unwrap(),
|
||||||
|
Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints deprecation warnings for deprecated options
|
/// Prints deprecation warnings for deprecated options
|
||||||
|
|
11
src/test/run-make-fulldeps/exit-code/Makefile
Normal file
11
src/test/run-make-fulldeps/exit-code/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
-include ../tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) success.rs; [ $$? -eq 0 ]
|
||||||
|
$(RUSTC) --invalid-arg-foo; [ $$? -eq 1 ]
|
||||||
|
$(RUSTC) compile-error.rs; [ $$? -eq 1 ]
|
||||||
|
$(RUSTC) -Ztreat-err-as-bug compile-error.rs; [ $$? -eq 101 ]
|
||||||
|
$(RUSTDOC) -o $(TMPDIR)/exit-code success.rs; [ $$? -eq 0 ]
|
||||||
|
$(RUSTDOC) --invalid-arg-foo; [ $$? -eq 1 ]
|
||||||
|
$(RUSTDOC) compile-error.rs; [ $$? -eq 1 ]
|
||||||
|
$(RUSTDOC) lint-failure.rs; [ $$? -eq 1 ]
|
13
src/test/run-make-fulldeps/exit-code/compile-error.rs
Normal file
13
src/test/run-make-fulldeps/exit-code/compile-error.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
compile_error!("kaboom");
|
||||||
|
}
|
16
src/test/run-make-fulldeps/exit-code/lint-failure.rs
Normal file
16
src/test/run-make-fulldeps/exit-code/lint-failure.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(intra_doc_link_resolution_failure)]
|
||||||
|
|
||||||
|
/// [intradoc::failure]
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
14
src/test/run-make-fulldeps/exit-code/success.rs
Normal file
14
src/test/run-make-fulldeps/exit-code/success.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
/// Main function
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// ignore-test currently ICEs when using NLL (#52416)
|
||||||
|
|
||||||
// We used to ICE when moving out of a `*mut T` or `*const T`.
|
// We used to ICE when moving out of a `*mut T` or `*const T`.
|
||||||
|
|
||||||
struct T(u8);
|
struct T(u8);
|
||||||
|
|
|
@ -14,8 +14,7 @@ use std::io::prelude::*;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use common;
|
use common::{self, Config, Mode};
|
||||||
use common::Config;
|
|
||||||
use util;
|
use util;
|
||||||
|
|
||||||
use extract_gdb_version;
|
use extract_gdb_version;
|
||||||
|
@ -262,7 +261,7 @@ impl TestProps {
|
||||||
disable_ui_testing_normalization: false,
|
disable_ui_testing_normalization: false,
|
||||||
normalize_stdout: vec![],
|
normalize_stdout: vec![],
|
||||||
normalize_stderr: vec![],
|
normalize_stderr: vec![],
|
||||||
failure_status: 101,
|
failure_status: -1,
|
||||||
run_rustfix: false,
|
run_rustfix: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,6 +392,11 @@ impl TestProps {
|
||||||
|
|
||||||
if let Some(code) = config.parse_failure_status(ln) {
|
if let Some(code) = config.parse_failure_status(ln) {
|
||||||
self.failure_status = code;
|
self.failure_status = code;
|
||||||
|
} else {
|
||||||
|
self.failure_status = match config.mode {
|
||||||
|
Mode::RunFail => 101,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.run_rustfix {
|
if !self.run_rustfix {
|
||||||
|
|
|
@ -1170,12 +1170,10 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
|
fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
|
||||||
for line in proc_res.stderr.lines() {
|
match proc_res.status.code() {
|
||||||
if line.contains("error: internal compiler error") {
|
Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
|
||||||
self.fatal_proc_rec("compiler encountered internal error", proc_res);
|
None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
|
||||||
} else if line.contains(" panicked at ") {
|
_ => (),
|
||||||
self.fatal_proc_rec("compiler panicked", proc_res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue