mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
In Option::get_or_insert_with(), forget the None instead of dropping it.
This allows eliminating the `T: [const] Destruct` bounds and avoids generating an implicit `drop_in_place::<Option<T>>()` that will never do anything. Ideally, the compiler would prove that that drop is not necessary itself, but it currently doesn't, even with `const_precise_live_drops` enabled.
This commit is contained in:
@@ -1776,7 +1776,7 @@ pub fn get_or_insert(&mut self, value: T) -> &mut T {
|
||||
#[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
|
||||
pub const fn get_or_insert_default(&mut self) -> &mut T
|
||||
where
|
||||
T: [const] Default + [const] Destruct,
|
||||
T: [const] Default,
|
||||
{
|
||||
self.get_or_insert_with(T::default)
|
||||
}
|
||||
@@ -1804,10 +1804,25 @@ pub const fn get_or_insert_default(&mut self) -> &mut T
|
||||
pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
|
||||
where
|
||||
F: [const] FnOnce() -> T + [const] Destruct,
|
||||
T: [const] Destruct,
|
||||
{
|
||||
if let None = self {
|
||||
*self = Some(f());
|
||||
// The effect of the following statement is identical to
|
||||
// *self = Some(f());
|
||||
// except that it does not drop the old value of `*self`. This is not a leak, because
|
||||
// we just checked that the old value is `None`, which contains no fields to drop.
|
||||
// This implementation strategy
|
||||
//
|
||||
// * avoids needing a `T: [const] Destruct` bound, to the benefit of `const` callers,
|
||||
// * and avoids possibly compiling needless drop code (as would sometimes happen in the
|
||||
// previous implementation), to the benefit of non-`const` callers.
|
||||
//
|
||||
// FIXME(const-hack): It would be nice if this weird trick were made obsolete
|
||||
// (though that is likely to be hard/wontfix).
|
||||
//
|
||||
// It could also be expressed as `unsafe { core::ptr::write(self, Some(f())) }`, but
|
||||
// no reason is currently known to use additional unsafe code here.
|
||||
|
||||
mem::forget(mem::replace(self, Some(f())));
|
||||
}
|
||||
|
||||
// SAFETY: a `None` variant for `self` would have been replaced by a `Some`
|
||||
|
||||
@@ -495,6 +495,30 @@ const fn option_const_mut() {
|
||||
*/
|
||||
}
|
||||
|
||||
/// Test that `Option::get_or_insert_default` is usable in const contexts, including with types that
|
||||
/// do not satisfy `T: const Destruct`.
|
||||
#[test]
|
||||
fn const_get_or_insert_default() {
|
||||
const OPT_DEFAULT: Option<Vec<bool>> = {
|
||||
let mut x = None;
|
||||
x.get_or_insert_default();
|
||||
x
|
||||
};
|
||||
assert!(OPT_DEFAULT.is_some());
|
||||
}
|
||||
|
||||
/// Test that `Option::get_or_insert_with` is usable in const contexts, including with types that
|
||||
/// do not satisfy `T: const Destruct`.
|
||||
#[test]
|
||||
fn const_get_or_insert_with() {
|
||||
const OPT_WITH: Option<Vec<bool>> = {
|
||||
let mut x = None;
|
||||
x.get_or_insert_with(Vec::new);
|
||||
x
|
||||
};
|
||||
assert!(OPT_WITH.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unwrap_drop() {
|
||||
struct Dtor<'a> {
|
||||
|
||||
Reference in New Issue
Block a user