about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-06-25 16:57:11 +0200
committerSamuel Tardieu <sam@rfc1149.net>2025-07-16 11:59:51 +0200
commitb49e36041b697f600c4a4cda723b1ae440da7777 (patch)
tree92ff887ea7e8acb5d10e95e0deafd766b9d8df27
parent21943a905690819b595bb302858276e3846fb298 (diff)
downloadrust-b49e36041b697f600c4a4cda723b1ae440da7777.tar.gz
rust-b49e36041b697f600c4a4cda723b1ae440da7777.zip
`unsafe_derive_deserialize`: do not consider `pin!()` as `unsafe`
In Rust 1.88, the `pin!()` macro uses `unsafe` and triggers
`unsafe_derive_deserialize`.
-rw-r--r--clippy_lints/src/derive.rs5
-rw-r--r--tests/ui/unsafe_derive_deserialize.rs29
-rw-r--r--tests/ui/unsafe_derive_deserialize.stderr11
3 files changed, 44 insertions, 1 deletions
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index 062f7cef3a7..49dd1bb09c6 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -432,6 +432,11 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
         if let ExprKind::Block(block, _) = expr.kind
             && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+            && block
+                .span
+                .source_callee()
+                .and_then(|expr| expr.macro_def_id)
+                .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
         {
             return ControlFlow::Break(());
         }
diff --git a/tests/ui/unsafe_derive_deserialize.rs b/tests/ui/unsafe_derive_deserialize.rs
index 14371bc203b..d0022f3b6d9 100644
--- a/tests/ui/unsafe_derive_deserialize.rs
+++ b/tests/ui/unsafe_derive_deserialize.rs
@@ -82,3 +82,32 @@ impl H {
 }
 
 fn main() {}
+
+mod issue15120 {
+    macro_rules! uns {
+        ($e:expr) => {
+            unsafe { $e }
+        };
+    }
+
+    #[derive(serde::Deserialize)]
+    struct Foo;
+
+    impl Foo {
+        fn foo(&self) {
+            // Do not lint if `unsafe` comes from the `core::pin::pin!()` macro
+            std::pin::pin!(());
+        }
+    }
+
+    //~v unsafe_derive_deserialize
+    #[derive(serde::Deserialize)]
+    struct Bar;
+
+    impl Bar {
+        fn bar(&self) {
+            // Lint if `unsafe` comes from the another macro
+            _ = uns!(42);
+        }
+    }
+}
diff --git a/tests/ui/unsafe_derive_deserialize.stderr b/tests/ui/unsafe_derive_deserialize.stderr
index f2d4429f707..4b5dd6e61fc 100644
--- a/tests/ui/unsafe_derive_deserialize.stderr
+++ b/tests/ui/unsafe_derive_deserialize.stderr
@@ -36,5 +36,14 @@ LL | #[derive(Deserialize)]
    = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
    = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+  --> tests/ui/unsafe_derive_deserialize.rs:104:14
+   |
+LL |     #[derive(serde::Deserialize)]
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+   = note: this error originates in the derive macro `serde::Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors