1
Fork 0

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::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) {
&note, &note,
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 {

View file

@ -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

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 // 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);

View file

@ -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 {

View file

@ -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);
}
} }
} }