Change:
If I have a type , and a trait that is implemented for both and , is a valid way to get a reference from an object of type . But since beta 1.71, this emits a warning. I have no idea what the warning is trying to convey, what "double reference" is referring to, or what "the inner type" is. No response
cc
Ah. then I think this lint shouldn't apply to since can mean specifically to borrow . But I think this should still apply to and
(sorry)
WG-prioritization assigning priority (). label -I-prioritize +P-medium

Discussion:
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target .label = target type is set here <del> 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 </del> <ins> 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 </ins> lint_trivial_untranslatable_diag = diagnostic with static strings only

} #[derive(LintDiagnostic)] <del> #[diag(lint_suspicious_double_ref_op)] pub struct SuspiciousDoubleRefDiag<'a> { pub call: Symbol, </del> <ins> #[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> { </ins> pub ty: Ty<'a>, <del> pub op: &'static str, </del> } // pass_by_value.rs

use crate::context::LintContext; <del> use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag}; </del> <ins> use crate::lints::{ NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag, }; </ins> use crate::LateContext; use crate::LateLintPass; use rustc_hir::def::DefKind;

// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` // traits and ignore any other method call. <del> 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, </del> <ins> 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; </ins> }; let substs = cx .tcx .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id));

// (Re)check that it implements the noop diagnostic. let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return }; <del> let op = match name { sym::noop_method_borrow => "borrow", sym::noop_method_clone => "clone", sym::noop_method_deref => "deref", _ => return, }; </del> 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);

NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span }, ); } else { <del> cx.emit_spanned_lint( SUSPICIOUS_DOUBLE_REF_OP, span, SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op }, ) </del> <ins> 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, } </ins> } } }

<ins> // 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(); } </ins>