Skip to content

Commit

Permalink
Add custom ICE message that points to Clippy repo
Browse files Browse the repository at this point in the history
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
  • Loading branch information
phansch committed Nov 29, 2019
1 parent 350f3d6 commit 1fb522e
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ clippy_lints = { version = "0.0.212", path = "clippy_lints" }
regex = "1"
semver = "0.9"
rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
lazy_static = "1.0"

[dev-dependencies]
cargo_metadata = "0.9.0"
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
let array_size_threshold = conf.array_size_threshold;
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
store.register_early_pass(|| box as_conversions::AsConversions);
store.register_early_pass(|| box utils::internal_lints::ProduceIce);

store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
Expand Down Expand Up @@ -1058,6 +1059,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
LintId::of(&utils::internal_lints::PRODUCE_ICE),
]);

store.register_group(true, "clippy::all", Some("clippy"), vec![
Expand Down
39 changes: 39 additions & 0 deletions clippy_lints/src/utils/internal_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintAr
use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use syntax::ast;
use syntax::ast::{Crate as AstCrate, ItemKind, Name};
use syntax::source_map::Span;
use syntax_pos::symbol::SymbolStr;
use syntax::visit::FnKind;

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

declare_clippy_lint! {
/// **What it does:** Not an actual lint. This lint is only meant for testing our customized internal compiler
/// error message by calling `panic`.
///
/// **Why is this bad?** ICE in large quantities can damage your teeth
///
/// **Known problems:** None
///
/// **Example:**
/// Bad:
/// ```rust,ignore
/// 🍦🍦🍦🍦🍦
/// ```
pub PRODUCE_ICE,
internal,
"this message should not appear anywhere as we ICE before and don't emit the lint"
}

declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);

impl EarlyLintPass for ClippyLintsInternal {
Expand Down Expand Up @@ -302,3 +322,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OuterExpnDataPass {
}
}
}

declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);

impl EarlyLintPass for ProduceIce {
fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &ast::FnDecl, _: Span, _: ast::NodeId) {
if is_trigger_fn(fn_kind) {
panic!("Testing the ICE message");
}
}
}

fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
match fn_kind {
FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
ident.name.as_str() == "should_trigger_an_ice_in_clippy"
},
FnKind::Closure(..) => false,
}
}
63 changes: 62 additions & 1 deletion src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@
// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc::ty::TyCtxt;
use rustc_interface::interface;
use rustc_tools_util::*;

use lazy_static::lazy_static;
use std::borrow::Cow;
use std::panic;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};

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

const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";

lazy_static! {
static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
let hook = panic::take_hook();
panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
hook
};
}

fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
// Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
(*ICE_HOOK)(info);

// Separate the output with an empty line
eprintln!();

let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
rustc_errors::ColorConfig::Auto,
None,
false,
false,
None,
false,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

// a .span_bug or .bug call has already printed what
// it wants to print.
if !info.payload().is::<rustc_errors::ExplicitBug>() {
let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
handler.emit_diagnostic(&d);
handler.abort_if_errors_and_should_abort();
}

let xs: Vec<Cow<'static, str>> = vec![
"the compiler unexpectedly panicked. this is a bug.".into(),
format!("we would appreciate a bug report: {}", bug_report_url).into(),
format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown_version")).into(),
];

for note in &xs {
handler.note_without_error(&note);
}

// If backtraces are enabled, also print the query stack
let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);

if backtrace {
TyCtxt::try_print_query_stack();
}
}

pub fn main() {
rustc_driver::init_rustc_env_logger();
rustc_driver::install_ice_hook();
lazy_static::initialize(&ICE_HOOK);
exit(
rustc_driver::catch_fatal_errors(move || {
use std::env;
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/custom_ice_message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![deny(clippy::internal)]

fn should_trigger_an_ice_in_clippy() {}

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/custom_ice_message.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
thread 'rustc' panicked at 'Testing the ICE message', clippy_lints/src/utils/internal_lints.rs:333:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new

note: rustc unknown_version

0 comments on commit 1fb522e

Please sign in to comment.