diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_lint/messages.ftl | 8 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/noop_method_call.rs | 81 |
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 }, + ) + } } } |
