Skip to content

Commit a4b93eb

Browse files
committed
Take in account the unreachable! macro in the non_fmt_panic lint
1 parent 565710b commit a4b93eb

File tree

9 files changed

+160
-35
lines changed

9 files changed

+160
-35
lines changed

compiler/rustc_hir/src/lang_items.rs

-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ language_item_table! {
277277
Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
278278
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
279279
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
280-
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
281280
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
282281
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
283282
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;

compiler/rustc_lint/src/non_fmt_panic.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
4949
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
5050
if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
5151
if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
52+
let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
53+
5254
if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
5355
|| Some(def_id) == cx.tcx.lang_items().panic_fn()
54-
|| Some(def_id) == cx.tcx.lang_items().panic_str()
56+
|| f_diagnostic_name == Some(sym::panic_str)
5557
{
5658
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
5759
if matches!(
@@ -61,6 +63,22 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
6163
check_panic(cx, f, arg);
6264
}
6365
}
66+
} else if f_diagnostic_name == Some(sym::unreachable_display) {
67+
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
68+
if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
69+
check_panic(
70+
cx,
71+
f,
72+
// This is safe because we checked above that the callee is indeed
73+
// unreachable_display
74+
match &arg.kind {
75+
// Get the borrowed arg not the borrow
76+
hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
77+
_ => bug!("call to unreachable_display without borrow"),
78+
},
79+
);
80+
}
81+
}
6482
}
6583
}
6684
}
@@ -85,8 +103,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
85103
return;
86104
}
87105

88-
// Find the span of the argument to `panic!()`, before expansion in the
89-
// case of `panic!(some_macro!())`.
106+
// Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the
107+
// case of `panic!(some_macro!())` or `unreachable!(some_macro!())`.
90108
// We don't use source_callsite(), because this `panic!(..)` might itself
91109
// be expanded from another macro, in which case we want to stop at that
92110
// expansion.
@@ -319,6 +337,7 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
319337
| sym::std_panic_macro
320338
| sym::assert_macro
321339
| sym::debug_assert_macro
340+
| sym::unreachable_macro
322341
) {
323342
break;
324343
}

library/core/src/panicking.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub const fn panic(expr: &'static str) -> ! {
5050

5151
#[inline]
5252
#[track_caller]
53-
#[lang = "panic_str"] // needed for `non-fmt-panics` lint
53+
#[rustc_diagnostic_item = "panic_str"]
5454
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
5555
pub const fn panic_str(expr: &str) -> ! {
5656
panic_display(&expr);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: format argument must be a string literal
2+
--> $DIR/unreachable-arg.rs:15:18
3+
|
4+
LL | unreachable!(a);
5+
| ^
6+
|
7+
help: you might be missing a string literal to format with
8+
|
9+
LL | unreachable!("{}", a);
10+
| +++++
11+
12+
error: aborting due to previous error
13+

src/test/ui/macros/unreachable-arg.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// ignore-emscripten no processes
2+
3+
// revisions: edition_2015 edition_2021
4+
// [edition_2015]edition:2015
5+
// [edition_2021]edition:2021
6+
// [edition_2015]run-fail
7+
// [edition_2021]check-fail
8+
// [edition_2015]error-pattern:internal error: entered unreachable code: hello
9+
// [edition_2021]error-pattern:format argument must be a string literal
10+
11+
#![allow(non_fmt_panics)]
12+
13+
fn main() {
14+
let a = "hello";
15+
unreachable!(a);
16+
}

src/test/ui/macros/unreachable-format-arg.rs

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x}
88
// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5
99

10+
#![allow(non_fmt_panics)]
11+
1012
fn main() {
1113
let x = 5;
1214
unreachable!("x is {x}");

src/test/ui/non-fmt-panic.fixed

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ static S: &str = "{bla}";
1111
#[allow(unreachable_code)]
1212
fn main() {
1313
panic!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
14+
unreachable!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
1415
std::panic!("{}", "another one: }"); //~ WARN panic message contains a brace
1516
core::panic!("{}", "Hello {}"); //~ WARN panic message contains an unused formatting placeholder
1617
assert!(false, "{}", "{:03x} {test} bla");
@@ -24,6 +25,8 @@ fn main() {
2425
debug_assert!(false, "{}", "{{}} bla"); //~ WARN panic message contains braces
2526
panic!("{}", C); //~ WARN panic message is not a string literal
2627
panic!("{}", S); //~ WARN panic message is not a string literal
28+
unreachable!("{}", S); //~ WARN panic message is not a string literal
29+
unreachable!("{}", S); //~ WARN panic message is not a string literal
2730
std::panic::panic_any(123); //~ WARN panic message is not a string literal
2831
core::panic!("{}", &*"abc"); //~ WARN panic message is not a string literal
2932
std::panic::panic_any(Some(123)); //~ WARN panic message is not a string literal
@@ -41,8 +44,10 @@ fn main() {
4144
}
4245

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

4549
panic!("{}", 1); //~ WARN panic message is not a string literal
50+
unreachable!("{}", 1); //~ WARN panic message is not a string literal
4651
assert!(false, "{}", 1); //~ WARN panic message is not a string literal
4752
debug_assert!(false, "{}", 1); //~ WARN panic message is not a string literal
4853

src/test/ui/non-fmt-panic.rs

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ static S: &str = "{bla}";
1111
#[allow(unreachable_code)]
1212
fn main() {
1313
panic!("here's a brace: {"); //~ WARN panic message contains a brace
14+
unreachable!("here's a brace: {"); //~ WARN panic message contains a brace
1415
std::panic!("another one: }"); //~ WARN panic message contains a brace
1516
core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
1617
assert!(false, "{:03x} {test} bla");
@@ -24,6 +25,8 @@ fn main() {
2425
debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
2526
panic!(C); //~ WARN panic message is not a string literal
2627
panic!(S); //~ WARN panic message is not a string literal
28+
unreachable!(S); //~ WARN panic message is not a string literal
29+
unreachable!(S); //~ WARN panic message is not a string literal
2730
std::panic!(123); //~ WARN panic message is not a string literal
2831
core::panic!(&*"abc"); //~ WARN panic message is not a string literal
2932
panic!(Some(123)); //~ WARN panic message is not a string literal
@@ -41,8 +44,10 @@ fn main() {
4144
}
4245

4346
panic!(a!()); //~ WARN panic message is not a string literal
47+
unreachable!(a!()); //~ WARN panic message is not a string literal
4448

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

0 commit comments

Comments
 (0)