diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 59834c40915..6f9a42df069 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -5,13 +5,14 @@ use std::io::{self, Write}; use std::path::{self, Path, PathBuf}; use std::sync::Arc; +use failure::Error; use same_file::is_same_file; use serde_json; use core::manifest::TargetSourcePath; use core::profiles::{Lto, Profile}; use core::{PackageId, Target}; -use util::errors::{CargoResult, CargoResultExt, Internal}; +use util::errors::{CargoResult, CargoResultExt, Internal, ProcessError}; use util::paths; use util::{self, machine_message, Freshness, ProcessBuilder, process}; use util::{internal, join_paths, profile}; @@ -275,6 +276,19 @@ fn rustc<'a, 'cfg>( } } + fn internal_if_simple_exit_code(err: Error) -> Error { + // If a signal on unix (code == None) or an abnormal termination + // on Windows (codes like 0xC0000409), don't hide the error details. + match err + .downcast_ref::() + .as_ref() + .and_then(|perr| perr.exit.and_then(|e| e.code())) + { + Some(n) if n < 128 => Internal::new(err).into(), + _ => err, + } + } + state.running(&rustc); if json_messages { exec.exec_json( @@ -284,13 +298,14 @@ fn rustc<'a, 'cfg>( mode, &mut assert_is_empty, &mut |line| json_stderr(line, &package_id, &target), - ).map_err(Internal::new) + ) + .map_err(internal_if_simple_exit_code) .chain_err(|| format!("Could not compile `{}`.", name))?; } else if build_plan { state.build_plan(buildkey, rustc.clone(), outputs.clone()); } else { exec.exec_and_capture_output(rustc, &package_id, &target, mode, state) - .map_err(Internal::new) + .map_err(internal_if_simple_exit_code) .chain_err(|| format!("Could not compile `{}`.", name))?; } diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 928bddde6fc..5f5a69c8e38 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -4373,3 +4373,65 @@ fn target_filters_workspace_not_found() { .with_stderr("[ERROR] no library targets found in packages: a, b") .run(); } + +#[cfg(unix)] +#[test] +fn signal_display() { + // Cause the compiler to crash with a signal. + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + [dependencies] + pm = { path = "pm" } + "#, + ) + .file( + "src/lib.rs", + r#" + #[macro_use] + extern crate pm; + + #[derive(Foo)] + pub struct S; + "#, + ) + .file( + "pm/Cargo.toml", + r#" + [package] + name = "pm" + version = "0.1.0" + [lib] + proc-macro = true + "#, + ) + .file( + "pm/src/lib.rs", + r#" + extern crate proc_macro; + use proc_macro::TokenStream; + + #[proc_macro_derive(Foo)] + pub fn derive(_input: TokenStream) -> TokenStream { + std::process::abort() + } + "#, + ) + .build(); + + foo.cargo("build") + .with_stderr("\ +[COMPILING] pm [..] +[COMPILING] foo [..] +[ERROR] Could not compile `foo`. + +Caused by: + process didn't exit successfully: `rustc [..]` (signal: 6, SIGABRT: process abort signal) +") + .with_status(101) + .run(); +}