about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_lint/messages.ftl12
-rw-r--r--compiler/rustc_lint/src/lints.rs12
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs62
-rw-r--r--tests/ui/lint/issue-112489.rs17
4 files changed, 64 insertions, 39 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c66fcdec716..34b7e09576a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -479,13 +479,11 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
 lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
     .label = target type is set here
 
-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_suspicious_double_ref_clone =
+    using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
+
+lint_suspicious_double_ref_deref =
+    using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
 lint_trivial_untranslatable_diag = diagnostic with static strings only
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 89fa5713b73..2a17389f247 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1231,11 +1231,15 @@ pub struct NoopMethodCallDiag<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_suspicious_double_ref_op)]
-pub struct SuspiciousDoubleRefDiag<'a> {
-    pub call: Symbol,
+#[diag(lint_suspicious_double_ref_deref)]
+pub struct SuspiciousDoubleRefDerefDiag<'a> {
+    pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_clone)]
+pub struct SuspiciousDoubleRefCloneDiag<'a> {
     pub ty: Ty<'a>,
-    pub op: &'static str,
 }
 
 // pass_by_value.rs
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d054966459d..d56c35bb677 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,5 +1,7 @@
 use crate::context::LintContext;
-use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag};
+use crate::lints::{
+    NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag,
+};
 use crate::LateContext;
 use crate::LateLintPass;
 use rustc_hir::def::DefKind;
@@ -76,22 +78,22 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
 
         // 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) {
-            // Verify we are dealing with a method/associated function.
-            Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
-                // Check that we're dealing with a trait method for one of the traits we care about.
-                Some(trait_id)
-                    if matches!(
-                        cx.tcx.get_diagnostic_name(trait_id),
-                        Some(sym::Borrow | sym::Clone | sym::Deref)
-                    ) =>
-                {
-                    did
-                }
-                _ => return,
-            },
-            _ => return,
+
+        let Some((DefKind::AssocFn, did)) =
+            cx.typeck_results().type_dependent_def(expr.hir_id)
+        else {
+            return;
+        };
+
+        let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };
+
+        if !matches!(
+            cx.tcx.get_diagnostic_name(trait_id),
+            Some(sym::Borrow | sym::Clone | sym::Deref)
+        ) {
+            return;
         };
+
         let substs = cx
             .tcx
             .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id));
@@ -102,13 +104,6 @@ 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 };
 
-        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);
         let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
@@ -129,11 +124,22 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
                 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 },
-            )
+            match name {
+                // If `type_of(x) == T` and `x.borrow()` is used to get `&T`,
+                // then that should be allowed
+                sym::noop_method_borrow => return,
+                sym::noop_method_clone => cx.emit_spanned_lint(
+                    SUSPICIOUS_DOUBLE_REF_OP,
+                    span,
+                    SuspiciousDoubleRefCloneDiag { ty: expr_ty },
+                ),
+                sym::noop_method_deref => cx.emit_spanned_lint(
+                    SUSPICIOUS_DOUBLE_REF_OP,
+                    span,
+                    SuspiciousDoubleRefDerefDiag { ty: expr_ty },
+                ),
+                _ => return,
+            }
         }
     }
 }
diff --git a/tests/ui/lint/issue-112489.rs b/tests/ui/lint/issue-112489.rs
new file mode 100644
index 00000000000..559edf0e4f2
--- /dev/null
+++ b/tests/ui/lint/issue-112489.rs
@@ -0,0 +1,17 @@
+// check-pass
+use std::borrow::Borrow;
+
+struct S;
+
+trait T: Sized {
+    fn foo(self) {}
+}
+
+impl T for S {}
+impl T for &S {}
+
+fn main() {
+    let s = S;
+    s.borrow().foo();
+    s.foo();
+}