missing_panics_doc: Allow unwrap() and expect() inside const-only contexts (#15170)

changelog: [`missing_panics_doc`]: Allow unwrap() and expect()s in
const-only contexts

Fixes rust-lang/rust-clippy#15169.

As far as I can tell, this change keeps this lint in line with similar
issues and their fixes such as
https://github.com/rust-lang/rust-clippy/pull/13382 and
rust-lang/rust-clippy#10240, so I feel pretty confident that the
behavior it exhibits after this PR is correct.
This commit is contained in:
Samuel Tardieu 2025-06-29 17:12:04 +00:00 committed by GitHub
commit 1f76a23d4d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 70 additions and 3 deletions

View file

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item};
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{fulfill_or_allowed, is_doc_hidden, method_chain_args, return_ty};
use clippy_utils::{fulfill_or_allowed, is_doc_hidden, is_inside_always_const_context, method_chain_args, return_ty};
use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
use rustc_lint::LateContext;
use rustc_middle::ty;
@ -99,13 +99,16 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
let mut panic_span = None;
let typeck = cx.tcx.typeck_body(body_id);
for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| {
if is_inside_always_const_context(cx.tcx, expr.hir_id) {
return ControlFlow::<!>::Continue(());
}
if let Some(macro_call) = root_macro_call_first_node(cx, expr)
&& (is_panic(cx, macro_call.def_id)
|| matches!(
cx.tcx.get_diagnostic_name(macro_call.def_id),
Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro)
))
&& !cx.tcx.hir_is_inside_const_context(expr.hir_id)
&& !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
&& panic_span.is_none()
{

View file

@ -250,3 +250,31 @@ pub fn issue_12760<const N: usize>() {
}
}
}
/// This needs documenting
pub fn unwrap_expect_etc_in_const() {
let a = const { std::num::NonZeroUsize::new(1).unwrap() };
// This should still pass the lint even if it is guaranteed to panic at compile-time
let b = const { std::num::NonZeroUsize::new(0).unwrap() };
}
/// This needs documenting
pub const fn unwrap_expect_etc_in_const_fn_fails() {
//~^ missing_panics_doc
let a = std::num::NonZeroUsize::new(1).unwrap();
}
/// This needs documenting
pub const fn assert_in_const_fn_fails() {
//~^ missing_panics_doc
let x = 0;
if x == 0 {
panic!();
}
}
/// This needs documenting
pub const fn in_const_fn<const N: usize>(n: usize) {
//~^ missing_panics_doc
assert!(N > n);
}

View file

@ -180,5 +180,41 @@ note: first possible panic found here
LL | *v.last().expect("passed an empty thing")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 15 previous errors
error: docs for function which may panic missing `# Panics` section
--> tests/ui/missing_panics_doc.rs:262:1
|
LL | pub const fn unwrap_expect_etc_in_const_fn_fails() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
--> tests/ui/missing_panics_doc.rs:264:13
|
LL | let a = std::num::NonZeroUsize::new(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
--> tests/ui/missing_panics_doc.rs:268:1
|
LL | pub const fn assert_in_const_fn_fails() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
--> tests/ui/missing_panics_doc.rs:272:9
|
LL | panic!();
| ^^^^^^^^
error: docs for function which may panic missing `# Panics` section
--> tests/ui/missing_panics_doc.rs:277:1
|
LL | pub const fn in_const_fn<const N: usize>(n: usize) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
--> tests/ui/missing_panics_doc.rs:279:5
|
LL | assert!(N > n);
| ^^^^^^^^^^^^^^
error: aborting due to 18 previous errors