Skip to content

Commit 9b60e6c

Browse files
committed
Auto merge of #108312 - michaelwoerister:hash-set-not-hash-stable, r=eholk
Do not implement HashStable for HashSet (MCP 533) This PR removes all occurrences of `HashSet` in query results, replacing it either with `FxIndexSet` or with `UnordSet`, and then removes the `HashStable` implementation of `HashSet`. This is part of implementing [MCP 533](rust-lang/compiler-team#533), that is, removing the `HashStable` implementations of all collection types with unstable iteration order. The changes are mostly mechanical. The only place where additional sorting is happening is in Miri's override implementation of the `exported_symbols` query.
2 parents 38b9655 + b79f026 commit 9b60e6c

File tree

23 files changed

+127
-103
lines changed

23 files changed

+127
-103
lines changed

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
5858

5959
let mut reachable_non_generics: DefIdMap<_> = tcx
6060
.reachable_set(())
61-
.iter()
61+
.items()
6262
.filter_map(|&def_id| {
6363
// We want to ignore some FFI functions that are not exposed from
6464
// this crate. Reachable FFI functions can be lumped into two
@@ -136,7 +136,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
136136
};
137137
(def_id.to_def_id(), info)
138138
})
139-
.collect();
139+
.into();
140140

141141
if let Some(id) = tcx.proc_macro_decls_static(()) {
142142
reachable_non_generics.insert(

compiler/rustc_codegen_ssa/src/target_features.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_ast::ast;
22
use rustc_attr::InstructionSetAttr;
33
use rustc_data_structures::fx::FxHashMap;
4-
use rustc_data_structures::fx::FxHashSet;
4+
use rustc_data_structures::fx::FxIndexSet;
55
use rustc_errors::Applicability;
66
use rustc_hir::def::DefKind;
77
use rustc_hir::def_id::DefId;
@@ -418,7 +418,7 @@ pub fn from_target_feature(
418418

419419
/// Computes the set of target features used in a function for the purposes of
420420
/// inline assembly.
421-
fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxHashSet<Symbol> {
421+
fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
422422
let mut target_features = tcx.sess.unstable_target_features.clone();
423423
if tcx.def_kind(did).has_codegen_attrs() {
424424
let attrs = tcx.codegen_fn_attrs(did);

compiler/rustc_data_structures/src/stable_hasher.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -617,18 +617,10 @@ where
617617
}
618618
}
619619

620-
impl<K, R, HCX> HashStable<HCX> for ::std::collections::HashSet<K, R>
621-
where
622-
K: ToStableHashKey<HCX> + Eq,
623-
R: BuildHasher,
624-
{
625-
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
626-
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
627-
let key = key.to_stable_hash_key(hcx);
628-
key.hash_stable(hcx, hasher);
629-
});
630-
}
631-
}
620+
// It is not safe to implement HashStable for HashSet or any other collection type
621+
// with unstable but observable iteration order.
622+
// See https://github.com/rust-lang/compiler-team/issues/533 for further information.
623+
impl<V, HCX> !HashStable<HCX> for std::collections::HashSet<V> {}
632624

633625
impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
634626
where

compiler/rustc_data_structures/src/unord.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
109109
}
110110
}
111111

112+
impl<T> UnordItems<T, std::iter::Empty<T>> {
113+
pub fn empty() -> Self {
114+
UnordItems(std::iter::empty())
115+
}
116+
}
117+
112118
impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
113119
#[inline]
114120
pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> {
@@ -133,6 +139,20 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
133139
items
134140
}
135141

142+
#[inline]
143+
pub fn into_sorted_stable_ord(self, use_stable_sort: bool) -> Vec<T>
144+
where
145+
T: Ord + StableOrd,
146+
{
147+
let mut items: Vec<T> = self.0.collect();
148+
if use_stable_sort {
149+
items.sort();
150+
} else {
151+
items.sort_unstable()
152+
}
153+
items
154+
}
155+
136156
pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
137157
where
138158
T: ToStableHashKey<HCX>,
@@ -175,6 +195,11 @@ impl<V: Eq + Hash> UnordSet<V> {
175195
self.inner.len()
176196
}
177197

198+
#[inline]
199+
pub fn is_empty(&self) -> bool {
200+
self.inner.is_empty()
201+
}
202+
178203
#[inline]
179204
pub fn insert(&mut self, v: V) -> bool {
180205
self.inner.insert(v)
@@ -253,7 +278,7 @@ impl<V: Eq + Hash> UnordSet<V> {
253278
// We can safely extend this UnordSet from a set of unordered values because that
254279
// won't expose the internal ordering anywhere.
255280
#[inline]
256-
pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
281+
pub fn extend_unord<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
257282
self.inner.extend(items.0)
258283
}
259284

@@ -277,6 +302,12 @@ impl<V: Hash + Eq> FromIterator<V> for UnordSet<V> {
277302
}
278303
}
279304

305+
impl<V: Hash + Eq> From<FxHashSet<V>> for UnordSet<V> {
306+
fn from(value: FxHashSet<V>) -> Self {
307+
UnordSet { inner: value }
308+
}
309+
}
310+
280311
impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
281312
#[inline]
282313
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {

compiler/rustc_hir_analysis/src/check/intrinsicck.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::InlineAsmTemplatePiece;
2-
use rustc_data_structures::fx::FxHashSet;
2+
use rustc_data_structures::fx::FxIndexSet;
33
use rustc_hir as hir;
44
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
55
use rustc_session::lint;
@@ -51,7 +51,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
5151
template: &[InlineAsmTemplatePiece],
5252
is_input: bool,
5353
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
54-
target_features: &FxHashSet<Symbol>,
54+
target_features: &FxIndexSet<Symbol>,
5555
) -> Option<InlineAsmType> {
5656
let ty = (self.get_operand_ty)(expr);
5757
if ty.has_non_region_infer() {
@@ -201,7 +201,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
201201
// (!). In that case we still need the earlier check to verify that the
202202
// register class is usable at all.
203203
if let Some(feature) = feature {
204-
if !target_features.contains(&feature) {
204+
if !target_features.contains(feature) {
205205
let msg = &format!("`{}` target feature is not enabled", feature);
206206
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
207207
err.note(&format!(

compiler/rustc_hir_analysis/src/check_unused.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
1010
for item_def_id in tcx.hir().body_owners() {
1111
let imports = tcx.used_trait_imports(item_def_id);
1212
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
13-
used_trait_imports.extend(imports.items().copied());
13+
used_trait_imports.extend_unord(imports.items().copied());
1414
}
1515

1616
for &id in tcx.maybe_unused_trait_imports(()) {

compiler/rustc_middle/src/arena.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ macro_rules! arena_types {
9494
[] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
9595
[] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
9696
[decode] attribute: rustc_ast::Attribute,
97-
[] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
97+
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>,
98+
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>,
9899
[] hir_id_set: rustc_hir::HirIdSet,
99100

100101
// Interned types

compiler/rustc_middle/src/mir/query.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::mir::{Body, ConstantKind, Promoted};
44
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
5-
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_data_structures::unord::UnordSet;
66
use rustc_data_structures::vec_map::VecMap;
77
use rustc_errors::ErrorGuaranteed;
88
use rustc_hir as hir;
@@ -123,7 +123,7 @@ pub struct UnsafetyCheckResult {
123123
pub violations: Vec<UnsafetyViolation>,
124124

125125
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
126-
pub used_unsafe_blocks: FxHashSet<hir::HirId>,
126+
pub used_unsafe_blocks: UnordSet<hir::HirId>,
127127

128128
/// This is `Some` iff the item is not a closure.
129129
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,

compiler/rustc_middle/src/query/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ rustc_queries! {
764764
///
765765
/// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
766766
///`{ trait_f: impl_f, trait_g: impl_g }`
767-
query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> {
767+
query impl_item_implementor_ids(impl_id: DefId) -> &'tcx DefIdMap<DefId> {
768768
arena_cache
769769
desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
770770
}
@@ -906,8 +906,8 @@ rustc_queries! {
906906
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
907907
/// their respective impl (i.e., part of the derive macro)
908908
query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
909-
FxHashSet<LocalDefId>,
910-
FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
909+
LocalDefIdSet,
910+
LocalDefIdMap<Vec<(DefId, DefId)>>
911911
) {
912912
arena_cache
913913
desc { "finding live symbols in crate" }
@@ -1120,7 +1120,7 @@ rustc_queries! {
11201120
desc { "checking for private elements in public interfaces" }
11211121
}
11221122

1123-
query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> {
1123+
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
11241124
arena_cache
11251125
desc { "reachability" }
11261126
}
@@ -1229,7 +1229,7 @@ rustc_queries! {
12291229
separate_provide_extern
12301230
}
12311231

1232-
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
1232+
query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> {
12331233
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
12341234
}
12351235

@@ -1845,7 +1845,7 @@ rustc_queries! {
18451845
query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
18461846
desc { "fetching potentially unused trait imports" }
18471847
}
1848-
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
1848+
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet<Symbol> {
18491849
desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
18501850
}
18511851

compiler/rustc_middle/src/ty/context.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
3636
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3737
use rustc_data_structures::steal::Steal;
3838
use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal};
39+
use rustc_data_structures::unord::UnordSet;
3940
use rustc_errors::{
4041
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
4142
};
@@ -2486,7 +2487,9 @@ pub fn provide(providers: &mut ty::query::Providers) {
24862487
providers.maybe_unused_trait_imports =
24872488
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
24882489
providers.names_imported_by_glob_use = |tcx, id| {
2489-
tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
2490+
tcx.arena.alloc(UnordSet::from(
2491+
tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default(),
2492+
))
24902493
};
24912494

24922495
providers.extern_mod_stmt_cnum =

compiler/rustc_middle/src/ty/query.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use rustc_arena::TypedArena;
4141
use rustc_ast as ast;
4242
use rustc_ast::expand::allocator::AllocatorKind;
4343
use rustc_attr as attr;
44-
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
44+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
4545
use rustc_data_structures::steal::Steal;
4646
use rustc_data_structures::svh::Svh;
4747
use rustc_data_structures::sync::Lrc;
@@ -50,7 +50,9 @@ use rustc_data_structures::unord::UnordSet;
5050
use rustc_errors::ErrorGuaranteed;
5151
use rustc_hir as hir;
5252
use rustc_hir::def::{DefKind, DocLinkResMap};
53-
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
53+
use rustc_hir::def_id::{
54+
CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet,
55+
};
5456
use rustc_hir::hir_id::OwnerId;
5557
use rustc_hir::lang_items::{LangItem, LanguageItems};
5658
use rustc_hir::{Crate, ItemLocalId, TraitCandidate};

compiler/rustc_mir_transform/src/check_unsafety.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_data_structures::fx::FxHashSet;
1+
use rustc_data_structures::unord::{UnordItems, UnordSet};
22
use rustc_errors::struct_span_err;
33
use rustc_hir as hir;
44
use rustc_hir::def::DefKind;
@@ -24,7 +24,7 @@ pub struct UnsafetyChecker<'a, 'tcx> {
2424
param_env: ty::ParamEnv<'tcx>,
2525

2626
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
27-
used_unsafe_blocks: FxHashSet<HirId>,
27+
used_unsafe_blocks: UnordSet<HirId>,
2828
}
2929

3030
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
@@ -129,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
129129
let def_id = def_id.expect_local();
130130
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
131131
self.tcx.unsafety_check_result(def_id);
132-
self.register_violations(violations, used_unsafe_blocks.iter().copied());
132+
self.register_violations(violations, used_unsafe_blocks.items().copied());
133133
}
134134
},
135135
_ => {}
@@ -151,7 +151,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
151151
let local_def_id = def_id.expect_local();
152152
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
153153
self.tcx.unsafety_check_result(local_def_id);
154-
self.register_violations(violations, used_unsafe_blocks.iter().copied());
154+
self.register_violations(violations, used_unsafe_blocks.items().copied());
155155
}
156156
}
157157
}
@@ -268,14 +268,14 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
268268
.lint_root;
269269
self.register_violations(
270270
[&UnsafetyViolation { source_info, lint_root, kind, details }],
271-
[],
271+
UnordItems::empty(),
272272
);
273273
}
274274

275275
fn register_violations<'a>(
276276
&mut self,
277277
violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
278-
new_used_unsafe_blocks: impl IntoIterator<Item = HirId>,
278+
new_used_unsafe_blocks: UnordItems<HirId, impl Iterator<Item = HirId>>,
279279
) {
280280
let safety = self.body.source_scopes[self.source_info.scope]
281281
.local_data
@@ -308,9 +308,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
308308
}),
309309
};
310310

311-
new_used_unsafe_blocks.into_iter().for_each(|hir_id| {
312-
self.used_unsafe_blocks.insert(hir_id);
313-
});
311+
self.used_unsafe_blocks.extend_unord(new_used_unsafe_blocks);
314312
}
315313
fn check_mut_borrowing_layout_constrained_field(
316314
&mut self,
@@ -407,7 +405,7 @@ enum Context {
407405

408406
struct UnusedUnsafeVisitor<'a, 'tcx> {
409407
tcx: TyCtxt<'tcx>,
410-
used_unsafe_blocks: &'a FxHashSet<HirId>,
408+
used_unsafe_blocks: &'a UnordSet<HirId>,
411409
context: Context,
412410
unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>,
413411
}
@@ -458,7 +456,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
458456
fn check_unused_unsafe(
459457
tcx: TyCtxt<'_>,
460458
def_id: LocalDefId,
461-
used_unsafe_blocks: &FxHashSet<HirId>,
459+
used_unsafe_blocks: &UnordSet<HirId>,
462460
) -> Vec<(HirId, UnusedUnsafe)> {
463461
let body_id = tcx.hir().maybe_body_owned_by(def_id);
464462

@@ -505,7 +503,7 @@ fn unsafety_check_result(
505503
if body.is_custom_mir() {
506504
return tcx.arena.alloc(UnsafetyCheckResult {
507505
violations: Vec::new(),
508-
used_unsafe_blocks: FxHashSet::default(),
506+
used_unsafe_blocks: Default::default(),
509507
unused_unsafes: Some(Vec::new()),
510508
});
511509
}

0 commit comments

Comments
 (0)