Skip to content

Commit 8f4ccac

Browse files
committed
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.
1 parent 4f3c7a4 commit 8f4ccac

File tree

9 files changed

+110
-25
lines changed

9 files changed

+110
-25
lines changed

src/librustc_driver/lib.rs

+35-13
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ use std::cmp::max;
9494
use std::default::Default;
9595
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
9696
use std::env;
97+
use std::error::Error;
9798
use std::ffi::OsString;
99+
use std::fmt::{self, Display};
98100
use std::io::{self, Read, Write};
99101
use std::iter::repeat;
100102
use std::mem;
@@ -146,6 +148,12 @@ pub mod target_features {
146148
}
147149
}
148150

151+
/// Exit status code used for successful compilation and help output.
152+
pub const EXIT_SUCCESS: isize = 0;
153+
154+
/// Exit status code used for compilation failures and invalid flags.
155+
pub const EXIT_FAILURE: isize = 1;
156+
149157
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
150158
md#bug-reports";
151159

@@ -178,7 +186,7 @@ pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) ->
178186
pub fn run<F>(run_compiler: F) -> isize
179187
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
180188
{
181-
monitor(move || {
189+
let result = monitor(move || {
182190
let (result, session) = run_compiler();
183191
if let Err(CompileIncomplete::Errored(_)) = result {
184192
match session {
@@ -201,7 +209,11 @@ pub fn run<F>(run_compiler: F) -> isize
201209
}
202210
}
203211
});
204-
0
212+
213+
match result {
214+
Ok(()) => EXIT_SUCCESS,
215+
Err(_) => EXIT_FAILURE,
216+
}
205217
}
206218

207219
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
@@ -1625,20 +1637,30 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
16251637
}
16261638
}
16271639

1640+
#[derive(Debug)]
1641+
pub struct CompilationFailure;
1642+
1643+
impl Error for CompilationFailure {}
1644+
1645+
impl Display for CompilationFailure {
1646+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1647+
write!(f, "compilation had errors")
1648+
}
1649+
}
1650+
16281651
/// Run a procedure which will detect panics in the compiler and print nicer
16291652
/// error messages rather than just failing the test.
16301653
///
16311654
/// The diagnostic emitter yielded to the procedure should be used for reporting
16321655
/// errors of the compiler.
1633-
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
1634-
let result = in_rustc_thread(move || {
1656+
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
1657+
in_rustc_thread(move || {
16351658
f()
1636-
});
1637-
1638-
if let Err(value) = result {
1639-
// Thread panicked without emitting a fatal diagnostic
1640-
if !value.is::<errors::FatalErrorMarker>() {
1641-
// Emit a newline
1659+
}).map_err(|value| {
1660+
if value.is::<errors::FatalErrorMarker>() {
1661+
CompilationFailure
1662+
} else {
1663+
// Thread panicked without emitting a fatal diagnostic
16421664
eprintln!("");
16431665

16441666
let emitter =
@@ -1677,10 +1699,10 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
16771699
&note,
16781700
errors::Level::Note);
16791701
}
1680-
}
16811702

1682-
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
1683-
}
1703+
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
1704+
}
1705+
})
16841706
}
16851707

16861708
pub fn diagnostics_registry() -> errors::registry::Registry {

src/librustdoc/lib.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use errors::ColorConfig;
5757
use std::collections::{BTreeMap, BTreeSet};
5858
use std::default::Default;
5959
use std::env;
60+
use std::panic;
6061
use std::path::{Path, PathBuf};
6162
use std::process;
6263
use std::sync::mpsc::channel;
@@ -115,7 +116,7 @@ pub fn main() {
115116
syntax::with_globals(move || {
116117
get_args().map(|args| main_args(&args)).unwrap_or(1)
117118
})
118-
}).unwrap().join().unwrap_or(101);
119+
}).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE);
119120
process::exit(res as i32);
120121
}
121122

@@ -667,7 +668,7 @@ where R: 'static + Send,
667668

668669
let (tx, rx) = channel();
669670

670-
rustc_driver::monitor(move || syntax::with_globals(move || {
671+
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
671672
use rustc::session::config::Input;
672673

673674
let (mut krate, renderinfo) =
@@ -771,7 +772,11 @@ where R: 'static + Send,
771772

772773
tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap();
773774
}));
774-
rx.recv().unwrap()
775+
776+
match result {
777+
Ok(()) => rx.recv().unwrap(),
778+
Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
779+
}
775780
}
776781

777782
/// Prints deprecation warnings for deprecated options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) success.rs; [ $$? -eq 0 ]
5+
$(RUSTC) --invalid-arg-foo; [ $$? -eq 1 ]
6+
$(RUSTC) compile-error.rs; [ $$? -eq 1 ]
7+
$(RUSTC) -Ztreat-err-as-bug compile-error.rs; [ $$? -eq 101 ]
8+
$(RUSTDOC) -o $(TMPDIR)/exit-code success.rs; [ $$? -eq 0 ]
9+
$(RUSTDOC) --invalid-arg-foo; [ $$? -eq 1 ]
10+
$(RUSTDOC) compile-error.rs; [ $$? -eq 1 ]
11+
$(RUSTDOC) lint-failure.rs; [ $$? -eq 1 ]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
compile_error!("kaboom");
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(intra_doc_link_resolution_failure)]
12+
13+
/// [intradoc::failure]
14+
fn main() {
15+
println!("Hello, world!");
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
/// Main function
12+
fn main() {
13+
println!("Hello, world!");
14+
}

src/test/ui/issue-20801.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// ignore-test currently ICEs when using NLL (#52416)
12+
1113
// We used to ICE when moving out of a `*mut T` or `*const T`.
1214

1315
struct T(u8);

src/tools/compiletest/src/header.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use std::io::prelude::*;
1414
use std::io::BufReader;
1515
use std::path::{Path, PathBuf};
1616

17-
use common;
18-
use common::Config;
17+
use common::{self, Config, Mode};
1918
use util;
2019

2120
use extract_gdb_version;
@@ -262,7 +261,7 @@ impl TestProps {
262261
disable_ui_testing_normalization: false,
263262
normalize_stdout: vec![],
264263
normalize_stderr: vec![],
265-
failure_status: 101,
264+
failure_status: -1,
266265
run_rustfix: false,
267266
}
268267
}
@@ -393,6 +392,11 @@ impl TestProps {
393392

394393
if let Some(code) = config.parse_failure_status(ln) {
395394
self.failure_status = code;
395+
} else {
396+
self.failure_status = match config.mode {
397+
Mode::RunFail => 101,
398+
_ => 1,
399+
};
396400
}
397401

398402
if !self.run_rustfix {

src/tools/compiletest/src/runtest.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1170,12 +1170,10 @@ impl<'test> TestCx<'test> {
11701170
}
11711171

11721172
fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
1173-
for line in proc_res.stderr.lines() {
1174-
if line.contains("error: internal compiler error") {
1175-
self.fatal_proc_rec("compiler encountered internal error", proc_res);
1176-
} else if line.contains(" panicked at ") {
1177-
self.fatal_proc_rec("compiler panicked", proc_res);
1178-
}
1173+
match proc_res.status.code() {
1174+
Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
1175+
None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
1176+
_ => (),
11791177
}
11801178
}
11811179

0 commit comments

Comments
 (0)