Skip to content

Commit 1ae6f47

Browse files
authored
Rollup merge of #133696 - RalfJung:const-hashmap, r=cuviper
stabilize const_collections_with_hasher and build_hasher_default_const_new After a lot of preparatory work, finally we can stabilize creating `HashMap` in const context. :) FCP for const_collections_with_hasher passed in #102575. Fixes #102575. FCP for build_hasher_default_const_new passed in #123197. Fixes #123197. Cc `@Amanieu` Release notes: #133347
2 parents 49df325 + 7ac7b4c commit 1ae6f47

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

library/core/src/hash/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -752,10 +752,10 @@ pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
752752

753753
impl<H> BuildHasherDefault<H> {
754754
/// Creates a new BuildHasherDefault for Hasher `H`.
755-
#[unstable(
755+
#[stable(feature = "build_hasher_default_const_new", since = "CURRENT_RUSTC_VERSION")]
756+
#[rustc_const_stable(
756757
feature = "build_hasher_default_const_new",
757-
issue = "123197",
758-
reason = "recently added"
758+
since = "CURRENT_RUSTC_VERSION"
759759
)]
760760
pub const fn new() -> Self {
761761
BuildHasherDefault(marker::PhantomData)

library/std/src/collections/hash/map.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ use crate::ops::Index;
204204
/// println!("{viking:?} has {health} hp");
205205
/// }
206206
/// ```
207+
///
208+
/// # Usage in `const` and `static`
209+
///
210+
/// As explained above, `HashMap` is randomly seeded: each `HashMap` instance uses a different seed,
211+
/// which means that `HashMap::new` cannot be used in const context. To construct a `HashMap` in the
212+
/// initializer of a `const` or `static` item, you will have to use a different hasher that does not
213+
/// involve a random seed, as demonstrated in the following example. **A `HashMap` constructed this
214+
/// way is not resistant against HashDoS!**
215+
///
216+
/// ```rust
217+
/// use std::collections::HashMap;
218+
/// use std::hash::{BuildHasherDefault, DefaultHasher};
219+
/// use std::sync::Mutex;
220+
///
221+
/// const EMPTY_MAP: HashMap<String, Vec<i32>, BuildHasherDefault<DefaultHasher>> =
222+
/// HashMap::with_hasher(BuildHasherDefault::new());
223+
/// static MAP: Mutex<HashMap<String, Vec<i32>, BuildHasherDefault<DefaultHasher>>> =
224+
/// Mutex::new(HashMap::with_hasher(BuildHasherDefault::new()));
225+
/// ```
207226
208227
#[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")]
209228
#[stable(feature = "rust1", since = "1.0.0")]
@@ -277,7 +296,10 @@ impl<K, V, S> HashMap<K, V, S> {
277296
/// ```
278297
#[inline]
279298
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
280-
#[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")]
299+
#[rustc_const_stable(
300+
feature = "const_collections_with_hasher",
301+
since = "CURRENT_RUSTC_VERSION"
302+
)]
281303
pub const fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
282304
HashMap { base: base::HashMap::with_hasher(hash_builder) }
283305
}

library/std/src/collections/hash/set.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,25 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub};
101101
/// [`HashMap`]: crate::collections::HashMap
102102
/// [`RefCell`]: crate::cell::RefCell
103103
/// [`Cell`]: crate::cell::Cell
104+
///
105+
/// # Usage in `const` and `static`
106+
///
107+
/// Like `HashMap`, `HashSet` is randomly seeded: each `HashSet` instance uses a different seed,
108+
/// which means that `HashSet::new` cannot be used in const context. To construct a `HashSet` in the
109+
/// initializer of a `const` or `static` item, you will have to use a different hasher that does not
110+
/// involve a random seed, as demonstrated in the following example. **A `HashSet` constructed this
111+
/// way is not resistant against HashDoS!**
112+
///
113+
/// ```rust
114+
/// use std::collections::HashSet;
115+
/// use std::hash::{BuildHasherDefault, DefaultHasher};
116+
/// use std::sync::Mutex;
117+
///
118+
/// const EMPTY_SET: HashSet<String, BuildHasherDefault<DefaultHasher>> =
119+
/// HashSet::with_hasher(BuildHasherDefault::new());
120+
/// static SET: Mutex<HashSet<String, BuildHasherDefault<DefaultHasher>>> =
121+
/// Mutex::new(HashSet::with_hasher(BuildHasherDefault::new()));
122+
/// ```
104123
#[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")]
105124
#[stable(feature = "rust1", since = "1.0.0")]
106125
pub struct HashSet<T, S = RandomState> {
@@ -369,7 +388,10 @@ impl<T, S> HashSet<T, S> {
369388
/// ```
370389
#[inline]
371390
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
372-
#[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")]
391+
#[rustc_const_stable(
392+
feature = "const_collections_with_hasher",
393+
since = "CURRENT_RUSTC_VERSION"
394+
)]
373395
pub const fn with_hasher(hasher: S) -> HashSet<T, S> {
374396
HashSet { base: base::HashSet::with_hasher(hasher) }
375397
}

library/std/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@
320320
// Library features (core):
321321
// tidy-alphabetical-start
322322
#![feature(array_chunks)]
323-
#![feature(build_hasher_default_const_new)]
324323
#![feature(c_str_module)]
325324
#![feature(char_internals)]
326325
#![feature(clone_to_uninit)]

src/bootstrap/src/core/build_steps/test.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,10 @@ impl Step for Crate {
27562756
// `lib.rs` file, and a `lib.miri.rs` file exists in the same folder, we build that
27572757
// instead. But crucially we only do that for the library, not the test builds.
27582758
cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1");
2759+
// std needs to be built with `-Zforce-unstable-if-unmarked`. For some reason the builder
2760+
// does not set this directly, but relies on the rustc wrapper to set it, and we are not using
2761+
// the wrapper -- hence we have to set it ourselves.
2762+
cargo.rustflag("-Zforce-unstable-if-unmarked");
27592763
cargo
27602764
} else {
27612765
// Also prepare a sysroot for the target.

0 commit comments

Comments
 (0)