From c10101cf1c62e504da6378ebf969cec2b74dccfb Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Tue, 5 Apr 2022 22:48:47 -0400
Subject: [PATCH] Don't lint `trivially_copy_pass_by_ref` when unsafe pointers
 are used

---
 clippy_lints/src/pass_by_ref_or_value.rs | 15 +++++++++++++++
 tests/ui/trivially_copy_pass_by_ref.rs   | 12 ++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs
index 6edf0e7a7b2..5fa4fd74853 100644
--- a/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/clippy_lints/src/pass_by_ref_or_value.rs
@@ -14,6 +14,7 @@ use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::{Adjust, PointerCast};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, RegionKind};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -185,6 +186,20 @@ impl<'tcx> PassByRefOrValue {
                         && size <= self.ref_min_size
                         && let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind
                     {
+                        if let Some(typeck) = cx.maybe_typeck_results() {
+                            // Don't lint if an unsafe pointer is created.
+                            // TODO: Limit the check only to unsafe pointers to the argument (or part of the argument)
+                            //       which escape the current function.
+                            if typeck.node_types().iter().any(|(_, &ty)| ty.is_unsafe_ptr())
+                                || typeck
+                                    .adjustments()
+                                    .iter()
+                                    .flat_map(|(_, a)| a)
+                                    .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer)))
+                            {
+                                continue;
+                            }
+                        }
                         let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) {
                             "self".into()
                         } else {
diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs
index 24117e37ed1..8f78f16a0a1 100644
--- a/tests/ui/trivially_copy_pass_by_ref.rs
+++ b/tests/ui/trivially_copy_pass_by_ref.rs
@@ -139,6 +139,18 @@ fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
     y
 }
 
+fn _return_ptr(x: &u32) -> *const u32 {
+    x
+}
+
+fn _return_field_ptr(x: &(u32, u32)) -> *const u32 {
+    &x.0
+}
+
+fn _return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 {
+    core::ptr::addr_of!(x.0)
+}
+
 fn main() {
     let (mut foo, bar) = (Foo(0), Bar([0; 24]));
     let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0);