@@ -103,26 +103,39 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
103
103
fn check_ty < ' tcx > ( cx : & LateContext < ' tcx > , span : Span , ty : Ty < ' tcx > ) {
104
104
let ty = ty. peel_refs ( ) ;
105
105
if let Adt ( def, substs) = ty. kind ( ) {
106
- if [ sym:: hashmap_type, sym:: BTreeMap , sym:: hashset_type, sym:: BTreeMap ]
106
+ let is_map_type = [ sym:: hashmap_type, sym:: BTreeMap , sym:: hashset_type, sym:: BTreeMap ]
107
107
. iter ( )
108
- . any ( |diag_item| cx. tcx . is_diagnostic_item ( * diag_item, def. did ) )
109
- && is_mutable_type ( cx, substs. type_at ( 0 ) , span)
110
- {
108
+ . any ( |diag_item| cx. tcx . is_diagnostic_item ( * diag_item, def. did ) ) ;
109
+ if is_map_type && is_mutable_type ( cx, substs. type_at ( 0 ) , span, true ) {
111
110
span_lint ( cx, MUTABLE_KEY_TYPE , span, "mutable key type" ) ;
112
111
}
113
112
}
114
113
}
115
114
116
- fn is_mutable_type < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , span : Span ) -> bool {
115
+ fn is_mutable_type < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , span : Span , is_top_level_type : bool ) -> bool {
117
116
match * ty. kind ( ) {
118
- RawPtr ( TypeAndMut { ty : inner_ty, mutbl } ) | Ref ( _, inner_ty, mutbl) => {
119
- mutbl == hir:: Mutability :: Mut || is_mutable_type ( cx, inner_ty, span)
117
+ RawPtr ( TypeAndMut { ty : inner_ty, mutbl } ) => {
118
+ if is_top_level_type {
119
+ // Raw pointers are hashed by the address they point to, not what is pointed to.
120
+ // Therefore, using a raw pointer to any type as the top-level key type is OK.
121
+ // Using raw pointers _in_ the key type is not, because the wrapper type could
122
+ // provide a custom `impl` for `Hash` (which could deref the raw pointer).
123
+ //
124
+ // see:
125
+ // - clippy issue: https://github.com/rust-lang/rust-clippy/issues/6745
126
+ // - std code: https://github.com/rust-lang/rust/blob/1.54.0/library/core/src/hash/mod.rs#L717-L736
127
+ false
128
+ } else {
129
+ mutbl == hir:: Mutability :: Mut || is_mutable_type ( cx, inner_ty, span, false )
130
+ }
120
131
} ,
121
- Slice ( inner_ty) => is_mutable_type ( cx, inner_ty, span) ,
132
+ Ref ( _, inner_ty, mutbl) => mutbl == hir:: Mutability :: Mut || is_mutable_type ( cx, inner_ty, span, false ) ,
133
+ Slice ( inner_ty) => is_mutable_type ( cx, inner_ty, span, false ) ,
122
134
Array ( inner_ty, size) => {
123
- size. try_eval_usize ( cx. tcx , cx. param_env ) . map_or ( true , |u| u != 0 ) && is_mutable_type ( cx, inner_ty, span)
135
+ size. try_eval_usize ( cx. tcx , cx. param_env ) . map_or ( true , |u| u != 0 )
136
+ && is_mutable_type ( cx, inner_ty, span, false )
124
137
} ,
125
- Tuple ( ..) => ty. tuple_fields ( ) . any ( |ty| is_mutable_type ( cx, ty, span) ) ,
138
+ Tuple ( ..) => ty. tuple_fields ( ) . any ( |ty| is_mutable_type ( cx, ty, span, false ) ) ,
126
139
Adt ( ..) => {
127
140
!ty. has_escaping_bound_vars ( )
128
141
&& cx. tcx . layout_of ( cx. param_env . and ( ty) ) . is_ok ( )
0 commit comments