about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndy Russell <arussell123@gmail.com>2018-07-09 14:01:10 -0400
committerAndy Russell <arussell123@gmail.com>2018-07-18 00:24:13 -0400
commit8f4ccac5e24ab9f0a786a87eb08d633c28d076ef (patch)
tree89cfe1ff1d4d0cc12f0babd436919d6d44f7650b
parent4f3c7a472b77ba3f3afbc12d004b9d1bbcee7fe7 (diff)
downloadrust-8f4ccac5e24ab9f0a786a87eb08d633c28d076ef.tar.gz
rust-8f4ccac5e24ab9f0a786a87eb08d633c28d076ef.zip
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.
-rw-r--r--src/librustc_driver/lib.rs48
-rw-r--r--src/librustdoc/lib.rs11
-rw-r--r--src/test/run-make-fulldeps/exit-code/Makefile11
-rw-r--r--src/test/run-make-fulldeps/exit-code/compile-error.rs13
-rw-r--r--src/test/run-make-fulldeps/exit-code/lint-failure.rs16
-rw-r--r--src/test/run-make-fulldeps/exit-code/success.rs14
-rw-r--r--src/test/ui/issue-20801.rs2
-rw-r--r--src/tools/compiletest/src/header.rs10
-rw-r--r--src/tools/compiletest/src/runtest.rs10
9 files changed, 110 insertions, 25 deletions
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 0e1ba6e444d..f60954ea021 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -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 {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 3e26ed2b97c..089ecebbc9c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -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
diff --git a/src/test/run-make-fulldeps/exit-code/Makefile b/src/test/run-make-fulldeps/exit-code/Makefile
new file mode 100644
index 00000000000..007f19852a6
--- /dev/null
+++ b/src/test/run-make-fulldeps/exit-code/Makefile
@@ -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 ]
diff --git a/src/test/run-make-fulldeps/exit-code/compile-error.rs b/src/test/run-make-fulldeps/exit-code/compile-error.rs
new file mode 100644
index 00000000000..8c05318a508
--- /dev/null
+++ b/src/test/run-make-fulldeps/exit-code/compile-error.rs
@@ -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");
+}
diff --git a/src/test/run-make-fulldeps/exit-code/lint-failure.rs b/src/test/run-make-fulldeps/exit-code/lint-failure.rs
new file mode 100644
index 00000000000..3bf40b753c1
--- /dev/null
+++ b/src/test/run-make-fulldeps/exit-code/lint-failure.rs
@@ -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!");
+}
diff --git a/src/test/run-make-fulldeps/exit-code/success.rs b/src/test/run-make-fulldeps/exit-code/success.rs
new file mode 100644
index 00000000000..9f6c5734a30
--- /dev/null
+++ b/src/test/run-make-fulldeps/exit-code/success.rs
@@ -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!");
+}
diff --git a/src/test/ui/issue-20801.rs b/src/test/ui/issue-20801.rs
index d3b97a9c058..0e8b7fb9037 100644
--- a/src/test/ui/issue-20801.rs
+++ b/src/test/ui/issue-20801.rs
@@ -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);
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 1dd7fe7f0cb..edab2a5ec03 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -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 {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 59ddc16715d..fcc47436225 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -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),
+            _ => (),
         }
     }