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:
Andy Russell 2018-07-09 14:01:10 -04:00
parent 4f3c7a472b
commit 8f4ccac5e2
No known key found for this signature in database
GPG Key ID: BE2221033EDBC374
9 changed files with 110 additions and 25 deletions

View File

@ -94,7 +94,9 @@ use std::cmp::max;
use std::default::Default;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::env;
use std::error::Error;
use std::ffi::OsString;
use std::fmt::{self, Display};
use std::io::{self, Read, Write};
use std::iter::repeat;
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.\
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
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
{
monitor(move || {
let result = monitor(move || {
let (result, session) = run_compiler();
if let Err(CompileIncomplete::Errored(_)) = result {
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> {
@ -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
/// error messages rather than just failing the test.
///
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
let result = in_rustc_thread(move || {
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
in_rustc_thread(move || {
f()
});
if let Err(value) = result {
// Thread panicked without emitting a fatal diagnostic
if !value.is::<errors::FatalErrorMarker>() {
// Emit a newline
}).map_err(|value| {
if value.is::<errors::FatalErrorMarker>() {
CompilationFailure
} else {
// Thread panicked without emitting a fatal diagnostic
eprintln!("");
let emitter =
@ -1677,10 +1699,10 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
&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 {

View File

@ -57,6 +57,7 @@ use errors::ColorConfig;
use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
use std::panic;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::mpsc::channel;
@ -115,7 +116,7 @@ pub fn main() {
syntax::with_globals(move || {
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);
}
@ -667,7 +668,7 @@ where R: 'static + Send,
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;
let (mut krate, renderinfo) =
@ -771,7 +772,11 @@ where R: 'static + Send,
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

View 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 ]

View 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");
}

View 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!");
}

View 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!");
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// 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`.
struct T(u8);

View File

@ -14,8 +14,7 @@ use std::io::prelude::*;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use common;
use common::Config;
use common::{self, Config, Mode};
use util;
use extract_gdb_version;
@ -262,7 +261,7 @@ impl TestProps {
disable_ui_testing_normalization: false,
normalize_stdout: vec![],
normalize_stderr: vec![],
failure_status: 101,
failure_status: -1,
run_rustfix: false,
}
}
@ -393,6 +392,11 @@ impl TestProps {
if let Some(code) = config.parse_failure_status(ln) {
self.failure_status = code;
} else {
self.failure_status = match config.mode {
Mode::RunFail => 101,
_ => 1,
};
}
if !self.run_rustfix {

View File

@ -1170,12 +1170,10 @@ impl<'test> TestCx<'test> {
}
fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
for line in proc_res.stderr.lines() {
if line.contains("error: internal compiler error") {
self.fatal_proc_rec("compiler encountered internal error", proc_res);
} else if line.contains(" panicked at ") {
self.fatal_proc_rec("compiler panicked", proc_res);
}
match proc_res.status.code() {
Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
_ => (),
}
}