From 7b76b947800bac94d041aaf8156450c8e7289da9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 22 Jun 2024 06:19:07 +0700 Subject: [PATCH 1/3] add test 12969 and 9841 --- tests/ui/explicit_auto_deref.fixed | 32 +++++++++++++++++++++++++++++ tests/ui/explicit_auto_deref.rs | 32 +++++++++++++++++++++++++++++ tests/ui/explicit_auto_deref.stderr | 14 ++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index e6ca4bb66cc..22bc0949659 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -345,3 +345,35 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 7531e1f87b7..2b3a28f8b6f 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -345,3 +345,35 @@ struct S8 { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&*wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 56a183de348..45059267362 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -271,5 +271,17 @@ error: deref which would be done by auto-deref LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` -error: aborting due to 45 previous errors +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:367:13 + | +LL | foo(&*wrapped_bar); + | ^^^^^^^^^^^^^ help: try: `wrapped_bar` + +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:373:21 + | +LL | takes_slice(*array) + | ^^^^^^ help: try: `array` + +error: aborting due to 47 previous errors From 388de386f5ecbbb0eb7a164fe1fa702db2fa4328 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 22 Jun 2024 06:21:35 +0700 Subject: [PATCH 2/3] Make it easier to print debugging with Debug --- clippy_lints/src/dereference.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 3c137b6b70f..4c1ca75e0db 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -175,6 +175,7 @@ struct StateData<'tcx> { adjusted_ty: Ty<'tcx>, } +#[derive(Debug)] struct DerefedBorrow { count: usize, msg: &'static str, @@ -182,6 +183,7 @@ struct DerefedBorrow { for_field_access: Option, } +#[derive(Debug)] enum State { // Any number of deref method calls. DerefMethod { @@ -744,7 +746,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum TyCoercionStability { Deref, Reborrow, From c4c41d135227a0a34ddc941ccb6be9296e4cceff Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 3 Jul 2024 21:25:43 +0700 Subject: [PATCH 3/3] Fix 12969 and fix 9841 --- clippy_lints/src/dereference.rs | 33 ++++++++++++++++++++--------- clippy_utils/src/lib.rs | 11 ++++++++++ tests/ui/explicit_auto_deref.fixed | 8 +++++-- tests/ui/explicit_auto_deref.rs | 4 ++++ tests/ui/explicit_auto_deref.stderr | 10 ++------- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 4c1ca75e0db..164d51ecb75 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,7 +3,8 @@ use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, + expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, + ExprUseNode, }; use core::mem; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; @@ -1044,16 +1045,28 @@ fn report<'tcx>( return; } - let (prefix, precedence) = if let Some(mutability) = mutability - && !typeck.expr_ty(expr).is_ref() + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, PREC_PREFIX) - } else { - ("", 0) + let (src, n_src_refs) = peel_middle_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, precedence) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, PREC_PREFIX) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0), + _ => ("", 0), }; span_lint_hir_and_then( cx, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fda870f435a..89686916671 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2471,6 +2471,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) } } +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { + let mut count = 0; + while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() { + ty = *dest_ty; + count += 1; + } + (ty, count) +} + /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 22bc0949659..255b2c5a220 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -364,13 +364,17 @@ mod issue_12969 { fn bar() { let wrapped_bar = Wrapper(""); - foo(wrapped_bar); + foo(&wrapped_bar); } } mod issue_9841 { fn takes_array_ref(array: &&[T; N]) { - takes_slice(array) + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) } fn takes_slice(slice: &[T]) { diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 2b3a28f8b6f..99906999f01 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -373,6 +373,10 @@ mod issue_9841 { takes_slice(*array) } + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + fn takes_slice(slice: &[T]) { todo!() } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 45059267362..53784934f63 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -275,13 +275,7 @@ error: deref which would be done by auto-deref --> tests/ui/explicit_auto_deref.rs:367:13 | LL | foo(&*wrapped_bar); - | ^^^^^^^^^^^^^ help: try: `wrapped_bar` + | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` -error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:373:21 - | -LL | takes_slice(*array) - | ^^^^^^ help: try: `array` - -error: aborting due to 47 previous errors +error: aborting due to 46 previous errors