Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit f7b3e4f

Browse files
committed
Auto merge of rust-lang#5056 - rust-lang:dissasociate-mut-key, r=flip1995
Avoid mut_key on types of unknown layout This fixes rust-lang#5020 by requiring a known layout for the key type before linting. Edit: This fixes rust-lang#5043, too. changelog: none
2 parents fd0428f + 59fd637 commit f7b3e4f

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

clippy_lints/src/mut_key.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
2-
use rustc::ty::{Adt, Dynamic, Opaque, Param, RawPtr, Ref, Ty, TypeAndMut};
2+
use rustc::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
33
use rustc_hir as hir;
44
use rustc_lint::{LateContext, LateLintPass};
55
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -101,21 +101,24 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
101101
if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
102102
.iter()
103103
.any(|path| match_def_path(cx, def.did, &**path))
104+
&& is_mutable_type(cx, substs.type_at(0), span)
104105
{
105-
let key_type = concrete_type(substs.type_at(0));
106-
if let Some(key_type) = key_type {
107-
if !key_type.is_freeze(cx.tcx, cx.param_env, span) {
108-
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
109-
}
110-
}
106+
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
111107
}
112108
}
113109
}
114110

115-
fn concrete_type(ty: Ty<'_>) -> Option<Ty<'_>> {
111+
fn is_mutable_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
116112
match ty.kind {
117-
RawPtr(TypeAndMut { ty: inner_ty, .. }) | Ref(_, inner_ty, _) => concrete_type(inner_ty),
118-
Dynamic(..) | Opaque(..) | Param(..) => None,
119-
_ => Some(ty),
113+
RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => {
114+
mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span)
115+
},
116+
Slice(inner_ty) => is_mutable_type(cx, inner_ty, span),
117+
Array(inner_ty, size) => {
118+
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span)
119+
},
120+
Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)),
121+
Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env, span),
122+
_ => false,
120123
}
121124
}

tests/ui/mut_key.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::implicit_hasher)]
2+
13
use std::collections::{HashMap, HashSet};
24
use std::hash::{Hash, Hasher};
35
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
@@ -29,9 +31,27 @@ fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<K
2931
m.keys().cloned().collect()
3032
}
3133

32-
fn this_is_ok(m: &mut HashMap<usize, Key>) {}
34+
fn this_is_ok(_m: &mut HashMap<usize, Key>) {}
35+
36+
#[allow(unused)]
37+
trait Trait {
38+
type AssociatedType;
39+
40+
fn trait_fn(&self, set: std::collections::HashSet<Self::AssociatedType>);
41+
}
42+
43+
fn generics_are_ok_too<K>(_m: &mut HashSet<K>) {
44+
// nothing to see here, move along
45+
}
46+
47+
fn tuples<U>(_m: &mut HashMap<((), U), ()>) {}
48+
49+
fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
3350

3451
fn main() {
3552
let _ = should_not_take_this_arg(&mut HashMap::new(), 1);
3653
this_is_ok(&mut HashMap::new());
54+
tuples::<Key>(&mut HashMap::new());
55+
tuples::<()>(&mut HashMap::new());
56+
tuples_bad::<()>(&mut HashMap::new());
3757
}

tests/ui/mut_key.stderr

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
error: mutable key type
2-
--> $DIR/mut_key.rs:27:32
2+
--> $DIR/mut_key.rs:29:32
33
|
44
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `#[deny(clippy::mutable_key_type)]` on by default
88

99
error: mutable key type
10-
--> $DIR/mut_key.rs:27:72
10+
--> $DIR/mut_key.rs:29:72
1111
|
1212
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
1313
| ^^^^^^^^^^^^
1414

1515
error: mutable key type
16-
--> $DIR/mut_key.rs:28:5
16+
--> $DIR/mut_key.rs:30:5
1717
|
1818
LL | let _other: HashMap<Key, bool> = HashMap::new();
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

21-
error: aborting due to 3 previous errors
21+
error: mutable key type
22+
--> $DIR/mut_key.rs:49:22
23+
|
24+
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
27+
error: aborting due to 4 previous errors
2228

0 commit comments

Comments
 (0)