about summary refs log tree commit diff
diff options
context:
space:
mode:
authoritsjunetime <junewelker@gmail.com>2025-06-29 10:54:13 -0600
committeritsjunetime <junewelker@gmail.com>2025-06-29 10:54:13 -0600
commitff3c9c15b7ae8a0ef7b4079b1c39ebb3a3bdbedb (patch)
treee72e55be9e3225cef28a5a145b3a3b9d8a276440
parent428208eb9b61f44e5bbab70feea42a8d55994230 (diff)
downloadrust-ff3c9c15b7ae8a0ef7b4079b1c39ebb3a3bdbedb.tar.gz
rust-ff3c9c15b7ae8a0ef7b4079b1c39ebb3a3bdbedb.zip
`missing_panics_doc`: Correctly distinguish maybe-const vs always-const contexts for missing_panics_doc
changelog: [`missing_panics_doc`]: Allow unwrap() and expect()s in const-only contexts
-rw-r--r--clippy_lints/src/doc/missing_headers.rs7
-rw-r--r--tests/ui/missing_panics_doc.rs28
-rw-r--r--tests/ui/missing_panics_doc.stderr38
3 files changed, 70 insertions, 3 deletions
diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs
index 9ee32fced8c..3033ac0d0b0 100644
--- a/clippy_lints/src/doc/missing_headers.rs
+++ b/clippy_lints/src/doc/missing_headers.rs
@@ -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()
         {
diff --git a/tests/ui/missing_panics_doc.rs b/tests/ui/missing_panics_doc.rs
index ffdae8504f7..d016e099e30 100644
--- a/tests/ui/missing_panics_doc.rs
+++ b/tests/ui/missing_panics_doc.rs
@@ -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);
+}
diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr
index 7f0acf8de9b..85a00914427 100644
--- a/tests/ui/missing_panics_doc.stderr
+++ b/tests/ui/missing_panics_doc.stderr
@@ -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