Skip to content

Commit 0f4035f

Browse files
committed
Auto merge of rust-lang#12976 - tesuji:fix-explicit_auto_deref, r=xFrednet
Fix some false-positive cases of `explicit_auto_deref` changelog: [`explicit_auto_deref`] Fix some false-positive cases Fix part of rust-lang#9841 Fix rust-lang#12969 r? xFrednet
2 parents 918ae1b + c4c41d1 commit 0f4035f

File tree

5 files changed

+116
-12
lines changed

5 files changed

+116
-12
lines changed

clippy_lints/src/dereference.rs

+26-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
33
use clippy_utils::sugg::has_enclosing_paren;
44
use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
55
use clippy_utils::{
6-
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
6+
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
7+
ExprUseNode,
78
};
89
use core::mem;
910
use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
@@ -175,13 +176,15 @@ struct StateData<'tcx> {
175176
adjusted_ty: Ty<'tcx>,
176177
}
177178

179+
#[derive(Debug)]
178180
struct DerefedBorrow {
179181
count: usize,
180182
msg: &'static str,
181183
stability: TyCoercionStability,
182184
for_field_access: Option<Symbol>,
183185
}
184186

187+
#[derive(Debug)]
185188
enum State {
186189
// Any number of deref method calls.
187190
DerefMethod {
@@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
744747
}
745748
}
746749

747-
#[derive(Clone, Copy)]
750+
#[derive(Clone, Copy, Debug)]
748751
enum TyCoercionStability {
749752
Deref,
750753
Reborrow,
@@ -1042,16 +1045,28 @@ fn report<'tcx>(
10421045
return;
10431046
}
10441047

1045-
let (prefix, precedence) = if let Some(mutability) = mutability
1046-
&& !typeck.expr_ty(expr).is_ref()
1048+
let ty = typeck.expr_ty(expr);
1049+
1050+
// `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst).
1051+
if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
1052+
&& dst.is_slice()
10471053
{
1048-
let prefix = match mutability {
1049-
Mutability::Not => "&",
1050-
Mutability::Mut => "&mut ",
1051-
};
1052-
(prefix, PREC_PREFIX)
1053-
} else {
1054-
("", 0)
1054+
let (src, n_src_refs) = peel_middle_ty_refs(ty);
1055+
if n_src_refs >= 2 && src.is_array() {
1056+
return;
1057+
}
1058+
}
1059+
1060+
let (prefix, precedence) = match mutability {
1061+
Some(mutability) if !ty.is_ref() => {
1062+
let prefix = match mutability {
1063+
Mutability::Not => "&",
1064+
Mutability::Mut => "&mut ",
1065+
};
1066+
(prefix, PREC_PREFIX)
1067+
},
1068+
None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0),
1069+
_ => ("", 0),
10551070
};
10561071
span_lint_hir_and_then(
10571072
cx,

clippy_utils/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -2492,6 +2492,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
24922492
}
24932493
}
24942494

2495+
/// Peels off all references on the type. Returns the underlying type and the number of references
2496+
/// removed.
2497+
pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
2498+
let mut count = 0;
2499+
while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
2500+
ty = *dest_ty;
2501+
count += 1;
2502+
}
2503+
(ty, count)
2504+
}
2505+
24952506
/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
24962507
/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
24972508
pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {

tests/ui/explicit_auto_deref.fixed

+36
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,39 @@ fn main() {
345345
let _ = &mut ({ *x.u }).x;
346346
}
347347
}
348+
349+
mod issue_12969 {
350+
use std::ops::Deref;
351+
352+
struct Wrapper<T>(T);
353+
354+
impl<T> Deref for Wrapper<T> {
355+
type Target = T;
356+
357+
fn deref(&self) -> &T {
358+
&self.0
359+
}
360+
}
361+
362+
fn foo(_bar: &str) {}
363+
364+
fn bar() {
365+
let wrapped_bar = Wrapper("");
366+
367+
foo(&wrapped_bar);
368+
}
369+
}
370+
371+
mod issue_9841 {
372+
fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
373+
takes_slice(*array)
374+
}
375+
376+
fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
377+
takes_slice(**array)
378+
}
379+
380+
fn takes_slice<T>(slice: &[T]) {
381+
todo!()
382+
}
383+
}

tests/ui/explicit_auto_deref.rs

+36
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,39 @@ fn main() {
345345
let _ = &mut ({ *x.u }).x;
346346
}
347347
}
348+
349+
mod issue_12969 {
350+
use std::ops::Deref;
351+
352+
struct Wrapper<T>(T);
353+
354+
impl<T> Deref for Wrapper<T> {
355+
type Target = T;
356+
357+
fn deref(&self) -> &T {
358+
&self.0
359+
}
360+
}
361+
362+
fn foo(_bar: &str) {}
363+
364+
fn bar() {
365+
let wrapped_bar = Wrapper("");
366+
367+
foo(&*wrapped_bar);
368+
}
369+
}
370+
371+
mod issue_9841 {
372+
fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
373+
takes_slice(*array)
374+
}
375+
376+
fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
377+
takes_slice(**array)
378+
}
379+
380+
fn takes_slice<T>(slice: &[T]) {
381+
todo!()
382+
}
383+
}

tests/ui/explicit_auto_deref.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,11 @@ error: deref which would be done by auto-deref
271271
LL | let _ = &mut (*{ x.u }).x;
272272
| ^^^^^^^^^^ help: try: `{ x.u }`
273273

274-
error: aborting due to 45 previous errors
274+
error: deref which would be done by auto-deref
275+
--> tests/ui/explicit_auto_deref.rs:367:13
276+
|
277+
LL | foo(&*wrapped_bar);
278+
| ^^^^^^^^^^^^^ help: try: `&wrapped_bar`
279+
280+
error: aborting due to 46 previous errors
275281

0 commit comments

Comments
 (0)