Skip to content

Commit

Permalink
Take in account the unreachable! macro in the non_fmt_panic lint
Browse files Browse the repository at this point in the history
  • Loading branch information
Urgau authored and Mark-Simulacrum committed Feb 11, 2022
1 parent 5140d6d commit 22f1800
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 35 deletions.
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ language_item_table! {
Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);

if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_str()
|| f_diagnostic_name == Some(sym::panic_str)
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if matches!(
Expand All @@ -61,6 +63,22 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
check_panic(cx, f, arg);
}
}
} else if f_diagnostic_name == Some(sym::unreachable_display) {
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
check_panic(
cx,
f,
// This is safe because we checked above that the callee is indeed
// unreachable_display
match &arg.kind {
// Get the borrowed arg not the borrow
hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
_ => bug!("call to unreachable_display without borrow"),
},
);
}
}
}
}
}
Expand All @@ -85,8 +103,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
return;
}

// Find the span of the argument to `panic!()`, before expansion in the
// case of `panic!(some_macro!())`.
// Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the
// case of `panic!(some_macro!())` or `unreachable!(some_macro!())`.
// We don't use source_callsite(), because this `panic!(..)` might itself
// be expanded from another macro, in which case we want to stop at that
// expansion.
Expand Down Expand Up @@ -319,6 +337,7 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
| sym::std_panic_macro
| sym::assert_macro
| sym::debug_assert_macro
| sym::unreachable_macro
) {
break;
}
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ pub const fn panic(expr: &'static str) -> ! {

#[inline]
#[track_caller]
#[lang = "panic_str"] // needed for `non-fmt-panics` lint
#[rustc_diagnostic_item = "panic_str"]
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_str(expr: &str) -> ! {
panic_display(&expr);
}
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/macros/unreachable-arg.edition_2021.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: format argument must be a string literal
--> $DIR/unreachable-arg.rs:15:18
|
LL | unreachable!(a);
| ^
|
help: you might be missing a string literal to format with
|
LL | unreachable!("{}", a);
| +++++

error: aborting due to previous error

16 changes: 16 additions & 0 deletions src/test/ui/macros/unreachable-arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ignore-emscripten no processes

// revisions: edition_2015 edition_2021
// [edition_2015]edition:2015
// [edition_2021]edition:2021
// [edition_2015]run-fail
// [edition_2021]check-fail
// [edition_2015]error-pattern:internal error: entered unreachable code: hello
// [edition_2021]error-pattern:format argument must be a string literal

#![allow(non_fmt_panics)]

fn main() {
let a = "hello";
unreachable!(a);
}
2 changes: 2 additions & 0 deletions src/test/ui/macros/unreachable-format-arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x}
// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5

#![allow(non_fmt_panics)]

fn main() {
let x = 5;
unreachable!("x is {x}");
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/non-fmt-panic.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ static S: &str = "{bla}";
#[allow(unreachable_code)]
fn main() {
panic!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
unreachable!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
std::panic!("{}", "another one: }"); //~ WARN panic message contains a brace
core::panic!("{}", "Hello {}"); //~ WARN panic message contains an unused formatting placeholder
assert!(false, "{}", "{:03x} {test} bla");
Expand All @@ -24,6 +25,8 @@ fn main() {
debug_assert!(false, "{}", "{{}} bla"); //~ WARN panic message contains braces
panic!("{}", C); //~ WARN panic message is not a string literal
panic!("{}", S); //~ WARN panic message is not a string literal
unreachable!("{}", S); //~ WARN panic message is not a string literal
unreachable!("{}", S); //~ WARN panic message is not a string literal
std::panic::panic_any(123); //~ WARN panic message is not a string literal
core::panic!("{}", &*"abc"); //~ WARN panic message is not a string literal
std::panic::panic_any(Some(123)); //~ WARN panic message is not a string literal
Expand All @@ -41,8 +44,10 @@ fn main() {
}

std::panic::panic_any(a!()); //~ WARN panic message is not a string literal
unreachable!("{}", a!()); //~ WARN panic message is not a string literal

panic!("{}", 1); //~ WARN panic message is not a string literal
unreachable!("{}", 1); //~ WARN panic message is not a string literal
assert!(false, "{}", 1); //~ WARN panic message is not a string literal
debug_assert!(false, "{}", 1); //~ WARN panic message is not a string literal

Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/non-fmt-panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ static S: &str = "{bla}";
#[allow(unreachable_code)]
fn main() {
panic!("here's a brace: {"); //~ WARN panic message contains a brace
unreachable!("here's a brace: {"); //~ WARN panic message contains a brace
std::panic!("another one: }"); //~ WARN panic message contains a brace
core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
assert!(false, "{:03x} {test} bla");
Expand All @@ -24,6 +25,8 @@ fn main() {
debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
panic!(C); //~ WARN panic message is not a string literal
panic!(S); //~ WARN panic message is not a string literal
unreachable!(S); //~ WARN panic message is not a string literal
unreachable!(S); //~ WARN panic message is not a string literal
std::panic!(123); //~ WARN panic message is not a string literal
core::panic!(&*"abc"); //~ WARN panic message is not a string literal
panic!(Some(123)); //~ WARN panic message is not a string literal
Expand All @@ -41,8 +44,10 @@ fn main() {
}

panic!(a!()); //~ WARN panic message is not a string literal
unreachable!(a!()); //~ WARN panic message is not a string literal

panic!(format!("{}", 1)); //~ WARN panic message is not a string literal
unreachable!(format!("{}", 1)); //~ WARN panic message is not a string literal
assert!(false, format!("{}", 1)); //~ WARN panic message is not a string literal
debug_assert!(false, format!("{}", 1)); //~ WARN panic message is not a string literal

Expand Down
Loading

0 comments on commit 22f1800

Please sign in to comment.