about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-05-09 23:48:17 +0200
committerSamuel Tardieu <sam@rfc1149.net>2025-05-10 00:20:55 +0200
commitbde939058b21dabcbd56b2fc55dacd36d1f97d49 (patch)
tree8b6018feed359f0111c88f043a4c29b0f04e4c42
parent16fd2a83d791d1a4eddbe620ebac37da208e25c4 (diff)
downloadrust-bde939058b21dabcbd56b2fc55dacd36d1f97d49.tar.gz
rust-bde939058b21dabcbd56b2fc55dacd36d1f97d49.zip
`char::is_digit()` is const-stable only since Rust 1.87
The `to_digit_is_some()` lint suggests using `char::is_digit()`. It
should not trigger in const contexts before Rust 1.87.
-rw-r--r--book/src/lint_configuration.md1
-rw-r--r--clippy_config/src/conf.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/to_digit_is_some.rs22
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--tests/ui/to_digit_is_some.fixed17
-rw-r--r--tests/ui/to_digit_is_some.rs17
-rw-r--r--tests/ui/to_digit_is_some.stderr14
8 files changed, 69 insertions, 7 deletions
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index 58c79c119cc..282d892951c 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -849,6 +849,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push)
 * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
 * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
+* [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some)
 * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)
 * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
 * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index aef0516b75b..8a1d38ed600 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -759,6 +759,7 @@ define_Conf! {
         same_item_push,
         seek_from_current,
         seek_rewind,
+        to_digit_is_some,
         transmute_ptr_to_ref,
         tuple_array_conversions,
         type_repetition_in_bounds,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index ad8b223b3aa..64fbc0252e2 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -746,7 +746,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf)));
     store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
     store.register_late_pass(|_| Box::new(exit::Exit));
-    store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
+    store.register_late_pass(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf)));
     store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf)));
     store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf)));
     store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs
index c8a6a41d6d8..7d7d74f27b3 100644
--- a/clippy_lints/src/to_digit_is_some.rs
+++ b/clippy_lints/src/to_digit_is_some.rs
@@ -1,10 +1,12 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{paths, sym};
+use clippy_utils::{is_in_const_context, paths, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -32,7 +34,17 @@ declare_clippy_lint! {
     "`char.is_digit()` is clearer"
 }
 
-declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
+impl_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
+
+pub(crate) struct ToDigitIsSome {
+    msrv: Msrv,
+}
+
+impl ToDigitIsSome {
+    pub(crate) fn new(conf: &'static Conf) -> Self {
+        Self { msrv: conf.msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
@@ -59,7 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                 _ => None,
             };
 
-            if let Some((is_method_call, char_arg, radix_arg)) = match_result {
+            if let Some((is_method_call, char_arg, radix_arg)) = match_result
+                && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_CHAR_IS_DIGIT))
+            {
                 let mut applicability = Applicability::MachineApplicable;
                 let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability);
                 let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 71985cb4b09..434e43167d6 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -23,7 +23,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
-    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
     1,85,0 { UINT_FLOAT_MIDPOINT }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed
index 627d54c5f73..ff6b32e6bd1 100644
--- a/tests/ui/to_digit_is_some.fixed
+++ b/tests/ui/to_digit_is_some.fixed
@@ -9,3 +9,20 @@ fn main() {
     let _ = char::is_digit(c, 8);
     //~^ to_digit_is_some
 }
+
+#[clippy::msrv = "1.86"]
+mod cannot_lint_in_const_context {
+    fn without_const(c: char) -> bool {
+        c.is_digit(8)
+        //~^ to_digit_is_some
+    }
+    const fn with_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+    }
+}
+
+#[clippy::msrv = "1.87"]
+const fn with_const(c: char) -> bool {
+    c.is_digit(8)
+    //~^ to_digit_is_some
+}
diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs
index d4eccc9931f..5ba08617433 100644
--- a/tests/ui/to_digit_is_some.rs
+++ b/tests/ui/to_digit_is_some.rs
@@ -9,3 +9,20 @@ fn main() {
     let _ = char::to_digit(c, 8).is_some();
     //~^ to_digit_is_some
 }
+
+#[clippy::msrv = "1.86"]
+mod cannot_lint_in_const_context {
+    fn without_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+        //~^ to_digit_is_some
+    }
+    const fn with_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+    }
+}
+
+#[clippy::msrv = "1.87"]
+const fn with_const(c: char) -> bool {
+    c.to_digit(8).is_some()
+    //~^ to_digit_is_some
+}
diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr
index f41382a60d5..5ffedb4683f 100644
--- a/tests/ui/to_digit_is_some.stderr
+++ b/tests/ui/to_digit_is_some.stderr
@@ -13,5 +13,17 @@ error: use of `.to_digit(..).is_some()`
 LL |     let _ = char::to_digit(c, 8).is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)`
 
-error: aborting due to 2 previous errors
+error: use of `.to_digit(..).is_some()`
+  --> tests/ui/to_digit_is_some.rs:16:9
+   |
+LL |         c.to_digit(8).is_some()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)`
+
+error: use of `.to_digit(..).is_some()`
+  --> tests/ui/to_digit_is_some.rs:26:5
+   |
+LL |     c.to_digit(8).is_some()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)`
+
+error: aborting due to 4 previous errors