about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs7
-rw-r--r--compiler/rustc_lint/messages.ftl8
-rw-r--r--compiler/rustc_lint/src/lints.rs8
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs81
4 files changed, 82 insertions, 22 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index c63e156beae..4baac4b5afc 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -40,7 +40,6 @@ use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
 use itertools::Itertools;
-use std::borrow::Borrow;
 use std::cell::OnceCell;
 use std::collections::BTreeSet;
 use std::ffi::OsString;
@@ -576,17 +575,17 @@ fn link_dwarf_object<'a>(
 
     impl<Relocations> ThorinSession<Relocations> {
         fn alloc_mmap(&self, data: Mmap) -> &Mmap {
-            (*self.arena_mmap.alloc(data)).borrow()
+            &*self.arena_mmap.alloc(data)
         }
     }
 
     impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
         fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
-            (*self.arena_data.alloc(data)).borrow()
+            &*self.arena_data.alloc(data)
         }
 
         fn alloc_relocation(&self, data: Relocations) -> &Relocations {
-            (*self.arena_relocations.alloc(data)).borrow()
+            &*self.arena_relocations.alloc(data)
         }
 
         fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 3c6dbb466db..71cf644eb50 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -50,6 +50,14 @@ lint_deprecated_lint_name =
 lint_renamed_or_removed_lint = {$msg}
     .suggestion = use the new name
 
+lint_suspicious_double_ref_op =
+    using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op ->
+        *[should_not_happen] [{$op}]
+        [deref] dereferencing
+        [borrow] borrowing
+        [clone] cloning
+    } the inner type
+
 lint_unknown_lint =
     unknown lint: `{$name}`
     .suggestion = did you mean
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 848f6a9ecb5..d7bacc6485f 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1150,6 +1150,14 @@ pub struct NoopMethodCallDiag<'a> {
     pub label: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_op)]
+pub struct SuspiciousDoubleRefDiag<'a> {
+    pub call: Symbol,
+    pub ty: Ty<'a>,
+    pub op: &'static str,
+}
+
 // pass_by_value.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_pass_by_value)]
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d67a00619dd..d054966459d 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,10 +1,11 @@
 use crate::context::LintContext;
-use crate::lints::NoopMethodCallDiag;
+use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag};
 use crate::LateContext;
 use crate::LateLintPass;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::symbol::sym;
 
 declare_lint! {
@@ -35,14 +36,44 @@ declare_lint! {
     "detects the use of well-known noop methods"
 }
 
-declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
+declare_lint! {
+    /// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
+    /// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
+    /// instead of performing the operation on the underlying `T` and can be confusing.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// struct Foo;
+    /// let foo = &&Foo;
+    /// let clone: &Foo = foo.clone();
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
+    /// reference, instead of cloning the inner type which should be what was intended.
+    pub SUSPICIOUS_DOUBLE_REF_OP,
+    Warn,
+    "suspicious call of trait method on `&&T`"
+}
+
+declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
 
 impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // We only care about method calls.
-        let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
-            return
+        let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
+            return;
         };
+
+        if call_span.from_expansion() {
+            return;
+        }
+
         // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
         // traits and ignore any other method call.
         let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
@@ -70,25 +101,39 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         };
         // (Re)check that it implements the noop diagnostic.
         let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
-        if !matches!(
-            name,
-            sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
-        ) {
-            return;
-        }
+
+        let op = match name {
+            sym::noop_method_borrow => "borrow",
+            sym::noop_method_clone => "clone",
+            sym::noop_method_deref => "deref",
+            _ => return,
+        };
+
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
         let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
-        if receiver_ty != expr_ty {
-            // This lint will only trigger if the receiver type and resulting expression \
-            // type are the same, implying that the method call is unnecessary.
+        let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
+
+        // If there is any user defined auto-deref step, then we don't want to warn.
+        // https://github.com/rust-lang/rust-clippy/issues/9272
+        if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
             return;
         }
+
         let expr_span = expr.span;
         let span = expr_span.with_lo(receiver.span.hi());
-        cx.emit_spanned_lint(
-            NOOP_METHOD_CALL,
-            span,
-            NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
-        );
+
+        if receiver_ty == expr_ty {
+            cx.emit_spanned_lint(
+                NOOP_METHOD_CALL,
+                span,
+                NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
+            );
+        } else {
+            cx.emit_spanned_lint(
+                SUSPICIOUS_DOUBLE_REF_OP,
+                span,
+                SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op },
+            )
+        }
     }
 }