Skip to content

Commit 676f14b

Browse files
committed
Add custom ICE message that points to Clippy repo
This utilizes rust-lang/rust#60584 by setting our own `panic_hook` and pointing to our own issue tracker instead of the rustc issue tracker. This also adds a new internal lint to test the ICE message. **Potential downsides** * This essentially copies rustc's `report_ice` function as `report_clippy_ice`. I think that's how it's meant to be implemented, but maybe @jonas-schievink could have a look as well =) The downside of more-or-less copying this function is that we have to maintain it as well now. The original function can be found [here][original]. * `driver` now depends directly on `rustc` and `rustc_errors` Closes rust-lang#2734 [original]: https://github.com/rust-lang/rust/blob/59367b074f1523353dddefa678ffe3cac9fd4e50/src/librustc_driver/lib.rs#L1185
1 parent 7d4e8e1 commit 676f14b

File tree

6 files changed

+120
-1
lines changed

6 files changed

+120
-1
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ semver = "0.9"
4040
rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
4141
git2 = { version = "0.10", optional = true }
4242
tempfile = { version = "3.1.0", optional = true }
43+
lazy_static = "1.0"
4344

4445
[dev-dependencies]
4546
cargo_metadata = "0.9.0"

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
963963
let array_size_threshold = conf.array_size_threshold;
964964
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
965965
store.register_early_pass(|| box as_conversions::AsConversions);
966+
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
966967

967968
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
968969
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1057,6 +1058,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
10571058
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
10581059
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
10591060
LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
1061+
LintId::of(&utils::internal_lints::PRODUCE_ICE),
10601062
]);
10611063

10621064
store.register_group(true, "clippy::all", Some("clippy"), vec![

clippy_lints/src/utils/internal_lints.rs

+39
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintAr
1111
use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
1212
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1313
use rustc_errors::Applicability;
14+
use syntax::ast;
1415
use syntax::ast::{Crate as AstCrate, ItemKind, Name};
1516
use syntax::source_map::Span;
1617
use syntax_pos::symbol::SymbolStr;
18+
use syntax::visit::FnKind;
1719

1820
declare_clippy_lint! {
1921
/// **What it does:** Checks for various things we like to keep tidy in clippy.
@@ -99,6 +101,24 @@ declare_clippy_lint! {
99101
"using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
100102
}
101103

104+
declare_clippy_lint! {
105+
/// **What it does:** Not an actual lint. This lint is only meant for testing our customized internal compiler
106+
/// error message by calling `panic`.
107+
///
108+
/// **Why is this bad?** ICE in large quantities can damage your teeth
109+
///
110+
/// **Known problems:** None
111+
///
112+
/// **Example:**
113+
/// Bad:
114+
/// ```rust,ignore
115+
/// 🍦🍦🍦🍦🍦
116+
/// ```
117+
pub PRODUCE_ICE,
118+
internal,
119+
"this message should not appear anywhere as we ICE before and don't emit the lint"
120+
}
121+
102122
declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
103123

104124
impl EarlyLintPass for ClippyLintsInternal {
@@ -302,3 +322,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OuterExpnDataPass {
302322
}
303323
}
304324
}
325+
326+
declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
327+
328+
impl EarlyLintPass for ProduceIce {
329+
fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &ast::FnDecl, _: Span, _: ast::NodeId) {
330+
if is_trigger_fn(fn_kind) {
331+
panic!("Testing the ICE message");
332+
}
333+
}
334+
}
335+
336+
fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
337+
match fn_kind {
338+
FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
339+
ident.name.as_str() == "should_trigger_an_ice_in_clippy"
340+
},
341+
FnKind::Closure(..) => false,
342+
}
343+
}

src/driver.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55
// FIXME: switch to something more ergonomic here, once available.
66
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
77
#[allow(unused_extern_crates)]
8+
extern crate rustc;
9+
#[allow(unused_extern_crates)]
810
extern crate rustc_driver;
911
#[allow(unused_extern_crates)]
12+
extern crate rustc_errors;
13+
#[allow(unused_extern_crates)]
1014
extern crate rustc_interface;
1115

16+
use rustc::ty::TyCtxt;
1217
use rustc_interface::interface;
1318
use rustc_tools_util::*;
1419

20+
use lazy_static::lazy_static;
21+
use std::borrow::Cow;
22+
use std::panic;
1523
use std::path::{Path, PathBuf};
1624
use std::process::{exit, Command};
1725

@@ -221,9 +229,62 @@ You can use tool lints to allow or deny lints from your code, eg.:
221229
);
222230
}
223231

232+
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
233+
234+
lazy_static! {
235+
static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
236+
let hook = panic::take_hook();
237+
panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
238+
hook
239+
};
240+
}
241+
242+
fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
243+
// Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
244+
(*ICE_HOOK)(info);
245+
246+
// Separate the output with an empty line
247+
eprintln!();
248+
249+
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
250+
rustc_errors::ColorConfig::Auto,
251+
None,
252+
false,
253+
false,
254+
None,
255+
false,
256+
));
257+
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
258+
259+
// a .span_bug or .bug call has already printed what
260+
// it wants to print.
261+
if !info.payload().is::<rustc_errors::ExplicitBug>() {
262+
let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
263+
handler.emit_diagnostic(&d);
264+
handler.abort_if_errors_and_should_abort();
265+
}
266+
267+
let xs: Vec<Cow<'static, str>> = vec![
268+
"the compiler unexpectedly panicked. this is a bug.".into(),
269+
format!("we would appreciate a bug report: {}", bug_report_url).into(),
270+
format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown_version")).into(),
271+
];
272+
273+
for note in &xs {
274+
handler.note_without_error(&note);
275+
}
276+
277+
// If backtraces are enabled, also print the query stack
278+
let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
279+
280+
if backtrace {
281+
TyCtxt::try_print_query_stack();
282+
}
283+
}
284+
224285
pub fn main() {
225286
rustc_driver::init_rustc_env_logger();
226-
rustc_driver::install_ice_hook();
287+
lazy_static::initialize(&ICE_HOOK);
227288
exit(
228289
rustc_driver::catch_fatal_errors(move || {
229290
use std::env;

tests/ui/custom_ice_message.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![deny(clippy::internal)]
2+
3+
fn should_trigger_an_ice_in_clippy() {}
4+
5+
fn main() {}

tests/ui/custom_ice_message.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
thread 'rustc' panicked at 'Testing the ICE message', clippy_lints/src/utils/internal_lints.rs:333:13
2+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
3+
4+
error: internal compiler error: unexpected panic
5+
6+
note: the compiler unexpectedly panicked. this is a bug.
7+
8+
note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
9+
10+
note: rustc unknown_version
11+

0 commit comments

Comments
 (0)