about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-19 13:46:15 +0000
committerbors <bors@rust-lang.org>2018-07-19 13:46:15 +0000
commita8247dd5c69ca57ede5073209bd30afb90dd4e3b (patch)
tree9e4448039b750a3c9f4ab55d8ece746bca816890
parent5ba21844f6c85a0cd55c8ea0250d5cd758134f84 (diff)
parent8f4ccac5e24ab9f0a786a87eb08d633c28d076ef (diff)
Auto merge of #52197 - euclio:exit-code, r=oli-obk
overhaul exit codes for rustc and rustdoc

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.

Note that while changes were made to the rustdoc binary, there is no
intended behavior change. rustdoc errors (i.e., failed lints) will still
report 101. While this could *also* hide potential ICEs, I will leave
that work to a future PR.

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),
+            _ => (),
         }
     }