Skip to content

Commit e261df4

Browse files
committed
Auto merge of #4588 - phansch:add_custom_ice_hook, r=Manishearth
Add custom ICE message that points to Clippy repo changelog: Link to Clippy issue tracker in ICE messages 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 #2734 [original]: https://github.com/rust-lang/rust/blob/59367b074f1523353dddefa678ffe3cac9fd4e50/src/librustc_driver/lib.rs#L1185
2 parents 1dc7f5c + 1814964 commit e261df4

File tree

6 files changed

+126
-2
lines changed

6 files changed

+126
-2
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ clippy_lints = { version = "0.0.212", path = "clippy_lints" }
4343
regex = "1"
4444
semver = "0.9"
4545
rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
46+
lazy_static = "1.0"
4647

4748
[dev-dependencies]
4849
cargo_metadata = "0.8.0"
4950
compiletest_rs = { version = "0.3.23", features = ["tmp"] }
50-
lazy_static = "1.0"
5151
clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
5252
serde = { version = "1.0", features = ["derive"] }
5353
derive-new = "0.5"

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
447447

448448
reg.register_late_lint_pass(box serde_api::SerdeAPI);
449449
reg.register_early_lint_pass(box utils::internal_lints::ClippyLintsInternal);
450+
reg.register_early_lint_pass(box utils::internal_lints::ProduceIce);
450451
reg.register_late_lint_pass(box utils::internal_lints::CompilerLintFunctions::new());
451452
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
452453
reg.register_late_lint_pass(box utils::internal_lints::OuterExpnDataPass);
@@ -690,6 +691,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
690691
utils::internal_lints::COMPILER_LINT_FUNCTIONS,
691692
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
692693
utils::internal_lints::OUTER_EXPN_EXPN_DATA,
694+
utils::internal_lints::PRODUCE_ICE,
693695
]);
694696

695697
reg.register_lint_group("clippy::all", Some("clippy"), vec![

clippy_lints/src/utils/internal_lints.rs

+39
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintAr
1010
use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
1111
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1212
use rustc_errors::Applicability;
13+
use syntax::ast;
1314
use syntax::ast::{Crate as AstCrate, ItemKind, Name};
1415
use syntax::source_map::Span;
16+
use syntax::visit::FnKind;
1517
use syntax_pos::symbol::LocalInternedString;
1618

1719
declare_clippy_lint! {
@@ -98,6 +100,24 @@ declare_clippy_lint! {
98100
"using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
99101
}
100102

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

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

src/driver.rs

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

15+
use rustc::ty::TyCtxt;
1116
use rustc_interface::interface;
1217
use rustc_tools_util::*;
1318

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

@@ -245,9 +253,64 @@ You can use tool lints to allow or deny lints from your code, eg.:
245253
);
246254
}
247255

256+
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
257+
258+
lazy_static! {
259+
static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
260+
let hook = panic::take_hook();
261+
panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
262+
hook
263+
};
264+
}
265+
266+
fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
267+
// Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
268+
(*ICE_HOOK)(info);
269+
270+
// Separate the output with an empty line
271+
eprintln!();
272+
273+
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
274+
rustc_errors::ColorConfig::Auto,
275+
None,
276+
false,
277+
false,
278+
None,
279+
false,
280+
));
281+
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
282+
283+
// a .span_bug or .bug call has already printed what
284+
// it wants to print.
285+
if !info.payload().is::<rustc_errors::ExplicitBug>() {
286+
let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
287+
handler.emit_diagnostic(&d);
288+
handler.abort_if_errors_and_should_abort();
289+
}
290+
291+
let version_info = rustc_tools_util::get_version_info!();
292+
293+
let xs: Vec<Cow<'static, str>> = vec![
294+
"the compiler unexpectedly panicked. this is a bug.".into(),
295+
format!("we would appreciate a bug report: {}", bug_report_url).into(),
296+
format!("Clippy version: {}", version_info).into(),
297+
];
298+
299+
for note in &xs {
300+
handler.note_without_error(&note);
301+
}
302+
303+
// If backtraces are enabled, also print the query stack
304+
let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
305+
306+
if backtrace {
307+
TyCtxt::try_print_query_stack(&handler);
308+
}
309+
}
310+
248311
pub fn main() {
249312
rustc_driver::init_rustc_env_logger();
250-
rustc_driver::install_ice_hook();
313+
lazy_static::initialize(&ICE_HOOK);
251314
exit(
252315
rustc_driver::catch_fatal_errors(move || {
253316
use std::env;

tests/ui/custom_ice_message.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// rustc-env:RUST_BACKTRACE=0
2+
// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
3+
// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs"
4+
5+
#![deny(clippy::internal)]
6+
7+
fn it_looks_like_you_are_trying_to_kill_clippy() {}
8+
9+
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
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: Clippy version: foo
11+

0 commit comments

Comments
 (0)