From fb715a4a113fe32980f117c5cb083484778df34c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 16:47:00 +0200 Subject: [PATCH 1/4] make closure-like types act like MaybeDangling --- compiler/rustc_codegen_ssa/src/mir/retag.rs | 2 +- .../src/interpret/validity.rs | 13 ++- compiler/rustc_middle/src/ty/adt.rs | 8 +- compiler/rustc_middle/src/ty/layout.rs | 29 +++---- compiler/rustc_middle/src/ty/sty.rs | 13 ++- .../fail/async-shared-mutable.stack.stderr | 8 +- .../fail/async-shared-mutable.tree.stderr | 8 +- .../maybe_dangling_unalighed.stderr | 2 +- .../fail/validity/maybe_dangling_null.stderr | 2 +- .../maybe_dangling_ref_too_big.stderr | 2 +- .../tests/pass/both_borrows/maybe_dangling.rs | 14 ++++ src/tools/miri/tests/pass/generators.rs | 80 +++++++++++++++++++ tests/codegen-llvm/maybe_dangling_refs.rs | 8 +- 13 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 src/tools/miri/tests/pass/generators.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/retag.rs b/compiler/rustc_codegen_ssa/src/mir/retag.rs index 397fb423e8da3..a71a57f02c82a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/retag.rs +++ b/compiler/rustc_codegen_ssa/src/mir/retag.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx, V> RetagPlan { // the outermost `Box` is what determines the permission that gets created. ty::Adt(adt, _) if adt.is_box() => Self::visit_box(bx, layout, is_fn_entry), // Skip traversing for everything inside of `MaybeDangling` - ty::Adt(adt, _) if adt.is_maybe_dangling() => None, + _ if layout.ty.is_like_maybe_dangling() => None, _ => Self::walk_value(bx, layout, is_fn_entry), } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 8c0bb1fcdd8a5..152b06499737c 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1528,15 +1528,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, BackendRepr::Memory { .. } => unreachable!() } } - ty::Adt(adt, _) if adt.is_maybe_dangling() => { - let old_may_dangle = mem::replace(&mut self.may_dangle, true); - - let inner = self.ecx.project_field(val, FieldIdx::ZERO)?; - self.visit_value(&inner)?; - - self.may_dangle = old_may_dangle; - } _ => { + let may_dangle = self.may_dangle || val.layout.ty.is_like_maybe_dangling(); + let old_may_dangle = mem::replace(&mut self.may_dangle, may_dangle); + // default handler try_validation!( self.walk_value(val), @@ -1546,6 +1541,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => InvalidMetaWrongTrait { expected_dyn_type, vtable_dyn_type }, ); + + self.may_dangle = old_may_dangle; } } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 0eea804b7cb53..af25d881f53bd 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -65,6 +65,8 @@ bitflags::bitflags! { /// Indicates whether the type is `FieldRepresentingType`. const IS_FIELD_REPRESENTING_TYPE = 1 << 13; /// Indicates whether the type is `MaybeDangling<_>`. + /// Note that this is not the only type with "maybe dangling" semantics! + /// Use `ty.is_like_maybe_dangling()` to check for that. const IS_MAYBE_DANGLING = 1 << 14; } } @@ -528,12 +530,6 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } - /// Returns `true` if this is `MaybeDangling`. - #[inline] - pub fn is_maybe_dangling(self) -> bool { - self.flags().contains(AdtFlags::IS_MAYBE_DANGLING) - } - /// Returns `true` if this is `Pin`. #[inline] pub fn is_pin(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index af2481f47c9ba..538a11cddf3c4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1090,20 +1090,6 @@ where }) } - ty::Adt(adt_def, ..) if adt_def.is_maybe_dangling() => { - Self::ty_and_layout_pointee_info_at(this.field(cx, 0), cx, offset).map(|info| { - PointeeInfo { - // Mark the pointer as raw - // (thus removing noalias/readonly/etc in case of the llvm backend) - safe: None, - // Make sure we don't assert dereferenceability of the pointer. - size: Size::ZERO, - // Preserve the alignment assertion! That is required even inside `MaybeDangling`. - align: info.align, - } - }) - } - _ => { let mut data_variant = match &this.variants { // Within the discriminant field, only the niche itself is @@ -1179,6 +1165,21 @@ where } } + // Patch result if we are a MaybeDangling-like type. + if this.ty.is_like_maybe_dangling() + && let Some(info) = result + { + result = Some(PointeeInfo { + // Mark the pointer as raw + // (thus removing noalias/readonly/etc in case of the llvm backend) + safe: None, + // Make sure we don't assert dereferenceability of the pointer. + size: Size::ZERO, + // Preserve the alignment assertion! That is required even inside `MaybeDangling`. + align: info.align, + }); + } + result } }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 054d4e18d3b70..10283e8e8bfb9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -23,7 +23,7 @@ use rustc_type_ir::{ use tracing::instrument; use ty::util::IntTypeExt; -use super::GenericParamDefKind; +use super::{AdtFlags, GenericParamDefKind}; use crate::infer::canonical::Canonical; use crate::traits::ObligationCause; use crate::ty::InferTy::*; @@ -2198,6 +2198,17 @@ impl<'tcx> Ty<'tcx> { pub fn walk(self) -> TypeWalker> { TypeWalker::new(self.into()) } + + /// Returns `true` if this is a `MaybeDangling`-like type, i.e., a type whose inner + /// references are not required to be dereferenceable and are not reborrowed. + #[inline] + pub fn is_like_maybe_dangling(self) -> bool { + match self.kind() { + ty::Adt(def, _) => def.flags().contains(AdtFlags::IS_MAYBE_DANGLING), + ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) => true, + _ => false, + } + } } impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List> { diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr index bdd004d5da99f..4435541bc0a1c 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr @@ -9,12 +9,8 @@ LL | *x = 1; help: was created by a Unique retag at offsets [RANGE] --> tests/fail/async-shared-mutable.rs:LL:CC | -LL | / core::future::poll_fn(move |_| { -LL | | *x = 1; -LL | | Poll::<()>::Pending -LL | | }) -LL | | .await - | |______________^ +LL | let x = &mut 0u8; + | ^^^^^^^^ help: was later invalidated at offsets [RANGE] by a SharedReadOnly retag --> tests/fail/async-shared-mutable.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index f9e75082758dd..bbb62a7e27b2b 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -10,12 +10,8 @@ LL | *x = 1; help: the accessed tag was created here, in the initial state Reserved --> tests/fail/async-shared-mutable.rs:LL:CC | -LL | / core::future::poll_fn(move |_| { -LL | | *x = 1; -LL | | Poll::<()>::Pending -LL | | }) -LL | | .await - | |______________^ +LL | let x = &mut 0u8; + | ^^^^^^^^ help: the accessed tag later transitioned to Unique due to a child write access at offsets [RANGE] --> tests/fail/async-shared-mutable.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr index 190976c4f046f..594c91352d796 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/maybe_dangling_unalighed.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u16>: at .0, encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs:LL:CC | LL | transmute::, MaybeDangling<&u16>>(unaligned) diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr index 041a6b1b96e0c..da8c88e16a1fe 100644 --- a/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_null.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: encountered a null reference +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&u8>: at .0, encountered a null reference --> tests/fail/validity/maybe_dangling_null.rs:LL:CC | LL | unsafe { transmute::, MaybeDangling<&u8>>(null) }; diff --git a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr index f0966586d4dc7..2c82b2719e711 100644 --- a/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr +++ b/src/tools/miri/tests/fail/validity/maybe_dangling_ref_too_big.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: encountered a reference that is too close to the end of the address space for a pointee of 1 bytes +error: Undefined Behavior: constructing invalid value of type std::mem::MaybeDangling<&i8>: at .0, encountered a reference that is too close to the end of the address space for a pointee of 1 bytes --> tests/fail/validity/maybe_dangling_ref_too_big.rs:LL:CC | LL | let _x: MaybeDangling<&i8> = unsafe { transmute(usize::MAX) }; diff --git a/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs index 028dcef8fa2d3..2d37344d24072 100644 --- a/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs +++ b/src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs @@ -14,6 +14,7 @@ fn main() { reference(); write_through_shared_ref(); large(); + closure(); } fn boxy() { @@ -64,3 +65,16 @@ fn large() { // Used to be rejected due to faulty logic for the "does this fit the address space" check. let _x: MaybeDangling<&i8> = unsafe { mem::transmute(usize::MAX - 127) }; } + +// A closure acts like MaybeDangling. +fn closure() { + fn invoke(f: impl FnOnce()) { + // The closure has captured a reference that will be freed while `invoke` runs. + f() + } + + let p = Box::leak(Box::new(0i32)); + invoke(move || { + drop(unsafe { Box::from_raw(p) }); + }); +} diff --git a/src/tools/miri/tests/pass/generators.rs b/src/tools/miri/tests/pass/generators.rs new file mode 100644 index 0000000000000..67a169bcfe821 --- /dev/null +++ b/src/tools/miri/tests/pass/generators.rs @@ -0,0 +1,80 @@ +//@edition: 2024 +#![feature(gen_blocks)] + +fn main() { + basic(); + iterate(); + movable_gen(); +} + +fn basic() { + gen fn foo() -> i32 { + yield 42; + for i in 5..10 { + if i % 2 == 0 { + continue; + } + yield i * 2; + } + } + + let v = foo().collect::>(); + assert_eq!(v, &[42, 10, 14, 18]); +} + +fn iterate() { + fn foo() -> impl Iterator { + gen { + yield 42; + for x in 3..6 { + yield x + } + } + } + + fn moved() -> impl Iterator { + let mut x = "foo".to_string(); + gen move { + yield 42; + if x == "foo" { + return; + } + x.clear(); + for x in 3..6 { + yield x + } + } + } + + let mut iter = foo(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(5)); + assert_eq!(iter.next(), None); + // `gen` blocks are fused + assert_eq!(iter.next(), None); + + let mut iter = moved(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), None); +} + +/// Ensure a generator can reborrow from a reference it captured. +/// Regression test for . +pub fn movable_gen() { + fn make_gen(r: &mut u8) -> impl Iterator { + gen move { + let a = r; + *a = 1; + yield 1; + *a = 2; + } + } + + let mut a = 1; + let mut i = make_gen(&mut a); + assert_eq!(i.next(), Some(1)); + let mut j = i; + assert_eq!(j.next(), None); +} diff --git a/tests/codegen-llvm/maybe_dangling_refs.rs b/tests/codegen-llvm/maybe_dangling_refs.rs index 07493ecac79c5..5d097151db4d7 100644 --- a/tests/codegen-llvm/maybe_dangling_refs.rs +++ b/tests/codegen-llvm/maybe_dangling_refs.rs @@ -7,7 +7,7 @@ #![crate_type = "lib"] #![feature(maybe_dangling)] -use std::mem::MaybeDangling; +use std::mem::{ManuallyDrop, MaybeDangling}; // CHECK: define {{(dso_local )?}}noundef nonnull ptr @f(ptr noundef nonnull %x) unnamed_addr #[no_mangle] @@ -15,6 +15,12 @@ pub fn f(x: MaybeDangling>) -> MaybeDangling> { x } +// CHECK: define {{(dso_local )?}}noundef nonnull ptr @f2(ptr noundef nonnull %x) unnamed_addr +#[no_mangle] +pub fn f2(x: ManuallyDrop>) -> ManuallyDrop> { + x +} + // CHECK: define {{(dso_local )?}}noundef nonnull ptr @g(ptr noundef nonnull %x) unnamed_addr #[no_mangle] pub fn g(x: MaybeDangling<&u8>) -> MaybeDangling<&u8> { From 4661008db575ef4e0d497c05ebf555c101e370ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 16:54:03 +0200 Subject: [PATCH 2/4] simplify ManuallyDrop by making it natively 'like MaybeDangling' --- compiler/rustc_middle/src/ty/sty.rs | 7 +- .../rustc_mir_build/src/builder/expr/into.rs | 4 +- library/core/src/mem/manually_drop.rs | 58 +-- src/etc/gdb_providers.py | 6 +- src/etc/natvis/libcore.natvis | 4 +- .../stacked_borrows/stack-printing.stdout | 4 +- ...move.box_new.CleanupPostBorrowck.after.mir | 2 +- ...ve.vec_macro.CleanupPostBorrowck.after.mir | 2 +- ...d_in_vec.build-{closure#0}.built.after.mir | 2 +- ....test.ElaborateDrops.after.panic-abort.mir | 2 +- ...test.ElaborateDrops.after.panic-unwind.mir | 2 +- ...loops.vec_move.runtime-optimized.after.mir | 376 +++++++++--------- .../future-sizes/async-awaiting-fut.stdout | 8 - .../async-await/future-sizes/large-arg.stdout | 6 - tests/ui/print_type_sizes/async.stdout | 4 - .../coroutine_discr_placement.stdout | 2 - 16 files changed, 208 insertions(+), 281 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 10283e8e8bfb9..ced0cb10c4dcf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2204,7 +2204,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_like_maybe_dangling(self) -> bool { match self.kind() { - ty::Adt(def, _) => def.flags().contains(AdtFlags::IS_MAYBE_DANGLING), + ty::Adt(def, _) => { + // ManuallyDrop is "natively" like maybe-dangling so that we don't have + // to nest field types even deeper. + def.flags().contains(AdtFlags::IS_MAYBE_DANGLING) + || def.flags().contains(AdtFlags::IS_MANUALLY_DROP) + } ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) => true, _ => false, } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 13a64346c36c4..1c9540b6e4323 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -452,9 +452,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = b.project_deeper(&[ProjectionElem::Deref], tcx); // Current type: `MaybeUninit`. Field #1 is `ManuallyDrop`. let place = place.project_to_field(FieldIdx::from_u32(1), decls, tcx); - // Current type: `ManuallyDrop`. Field #0 is `MaybeDangling`. - let place = place.project_to_field(FieldIdx::ZERO, decls, tcx); - // Current type: `MaybeDangling`. Field #0 is `T`. + // Current type: `ManuallyDrop`. Field #0 is `T`. let place = place.project_to_field(FieldIdx::ZERO, decls, tcx); // Sanity check. assert_eq!(place.ty(decls, tcx).ty, generic_args.type_at(0)); diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 6c2f77a373393..3fb844c7c2927 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,7 +1,5 @@ -use crate::cmp::Ordering; -use crate::hash::{Hash, Hasher}; -use crate::marker::{Destruct, StructuralPartialEq}; -use crate::mem::MaybeDangling; +use crate::hash::Hash; +use crate::marker::Destruct; use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; @@ -152,11 +150,11 @@ use crate::ptr; /// [`MaybeUninit`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] #[rustc_pub_transparent] pub struct ManuallyDrop { - value: MaybeDangling, + value: T, } impl ManuallyDrop { @@ -180,7 +178,7 @@ impl ManuallyDrop { #[inline(always)] #[rustc_no_writable] pub const fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value: MaybeDangling::new(value) } + ManuallyDrop { value } } /// Extracts the value from the `ManuallyDrop` container. @@ -198,9 +196,7 @@ impl ManuallyDrop { #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")] #[inline(always)] pub const fn into_inner(slot: ManuallyDrop) -> T { - // Cannot use `MaybeDangling::into_inner` as that does not yet have the desired semantics. - // SAFETY: We know this is a valid `T`. `slot` will not be dropped. - unsafe { (&raw const slot).cast::().read() } + slot.value } /// Takes the value from the `ManuallyDrop` container out. @@ -225,7 +221,7 @@ impl ManuallyDrop { pub const unsafe fn take(slot: &mut ManuallyDrop) -> T { // SAFETY: we are reading from a reference, which is guaranteed // to be valid for reads. - unsafe { ptr::read(slot.value.as_ref()) } + unsafe { ptr::read(&slot.value) } } } @@ -262,7 +258,7 @@ impl ManuallyDrop { // SAFETY: we are dropping the value pointed to by a mutable reference // which is guaranteed to be valid for writes. // It is up to the caller to make sure that `slot` isn't dropped again. - unsafe { ptr::drop_in_place(slot.value.as_mut()) } + unsafe { ptr::drop_in_place(&mut slot.value) } } } @@ -272,7 +268,7 @@ const impl Deref for ManuallyDrop { type Target = T; #[inline(always)] fn deref(&self) -> &T { - self.value.as_ref() + &self.value } } @@ -281,43 +277,9 @@ const impl Deref for ManuallyDrop { const impl DerefMut for ManuallyDrop { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - self.value.as_mut() + &mut self.value } } #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Eq for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl PartialEq for ManuallyDrop { - fn eq(&self, other: &Self) -> bool { - self.value.as_ref().eq(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl StructuralPartialEq for ManuallyDrop {} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Ord for ManuallyDrop { - fn cmp(&self, other: &Self) -> Ordering { - self.value.as_ref().cmp(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl PartialOrd for ManuallyDrop { - fn partial_cmp(&self, other: &Self) -> Option { - self.value.as_ref().partial_cmp(other.value.as_ref()) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Hash for ManuallyDrop { - fn hash(&self, state: &mut H) { - self.value.as_ref().hash(state); - } -} diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index a6ef59738c8c7..9c50d7e472000 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -330,7 +330,7 @@ def cast_to_internal(node): for i in xrange(0, length + 1): if height > 0: - child_ptr = edges[i]["value"]["value"][ZERO_FIELD] + child_ptr = edges[i]["value"]["value"] for child in children_of_node(child_ptr, height - 1): yield child if i < length: @@ -338,12 +338,12 @@ def cast_to_internal(node): key_type_size = keys.type.sizeof val_type_size = vals.type.sizeof key = ( - keys[i]["value"]["value"][ZERO_FIELD] + keys[i]["value"]["value"] if key_type_size > 0 else gdb.parse_and_eval("()") ) val = ( - vals[i]["value"]["value"][ZERO_FIELD] + vals[i]["value"]["value"] if val_type_size > 0 else gdb.parse_and_eval("()") ) diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 4e2f09743a031..20ce1cae447cf 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -35,9 +35,9 @@ - {value.__0} + {value} - value.__0 + value diff --git a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout index 296339e738455..838733078209d 100644 --- a/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout +++ b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout @@ -1,6 +1,6 @@ 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] 0..1: [ SharedReadWrite ] -0..1: [ SharedReadWrite Unique Unique Unique Unique Unique Unique Unique ] -0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] +0..1: [ SharedReadWrite Unique Unique Unique Unique Unique ] +0..1: [ SharedReadWrite Disabled Disabled Disabled Disabled Disabled SharedReadOnly ] 0..1: [ unknown-bottom(..) ] diff --git a/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir index 0050151e89b1b..158a1ea103a63 100644 --- a/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir +++ b/tests/mir-opt/building/write_box_via_move.box_new.CleanupPostBorrowck.after.mir @@ -23,7 +23,7 @@ fn box_new(_1: T) -> Box<[T; 1024]> { _4 = move _2; StorageLive(_5); _5 = copy _1; - ((((*_4).1: std::mem::ManuallyDrop<[T; 1024]>).0: std::mem::MaybeDangling<[T; 1024]>).0: [T; 1024]) = [move _5; 1024]; + (((*_4).1: std::mem::ManuallyDrop<[T; 1024]>).0: [T; 1024]) = [move _5; 1024]; StorageDead(_5); _3 = move _4; drop(_4) -> [return: bb2, unwind: bb5]; diff --git a/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir index 2410e4d31b486..d2f67cd6932c2 100644 --- a/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir +++ b/tests/mir-opt/building/write_box_via_move.vec_macro.CleanupPostBorrowck.after.mir @@ -12,7 +12,7 @@ fn vec_macro() -> Vec { } bb1: { - ((((*_2).1: std::mem::ManuallyDrop<[i32; 8]>).0: std::mem::MaybeDangling<[i32; 8]>).0: [i32; 8]) = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32, const 6_i32, const 7_i32]; + (((*_2).1: std::mem::ManuallyDrop<[i32; 8]>).0: [i32; 8]) = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32, const 6_i32, const 7_i32]; _1 = move _2; drop(_2) -> [return: bb2, unwind: bb4]; } diff --git a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir index fc75f261ea01b..6b9927949ffe2 100644 --- a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir +++ b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir @@ -91,7 +91,7 @@ yields () bb6: { StorageDead(_19); - ((((*_5).1: std::mem::ManuallyDrop<[std::string::String; 5]>).0: std::mem::MaybeDangling<[std::string::String; 5]>).0: [std::string::String; 5]) = [move _6, move _9, move _12, move _15, move _18]; + (((*_5).1: std::mem::ManuallyDrop<[std::string::String; 5]>).0: [std::string::String; 5]) = [move _6, move _9, move _12, move _15, move _18]; drop(_18) -> [return: bb7, unwind: bb25, drop: bb15]; } diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir index 968334753db40..de78225e309a8 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir @@ -55,7 +55,7 @@ fn test() -> Option> { _11 = copy ((_5 as Continue).0: u32); _4 = copy _11; StorageDead(_11); - ((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4]; + (((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: [u32; 1]) = [move _4]; StorageDead(_4); _2 = move _3; goto -> bb7; diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir index 1fc75018c8625..ba58ab81cd766 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir @@ -55,7 +55,7 @@ fn test() -> Option> { _11 = copy ((_5 as Continue).0: u32); _4 = copy _11; StorageDead(_11); - ((((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: std::mem::MaybeDangling<[u32; 1]>).0: [u32; 1]) = [move _4]; + (((*_3).1: std::mem::ManuallyDrop<[u32; 1]>).0: [u32; 1]) = [move _4]; StorageDead(_4); _2 = move _3; goto -> bb7; diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir index a49688ae891de..cad38c437e3c3 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.runtime-optimized.after.mir @@ -3,327 +3,309 @@ fn vec_move(_1: Vec) -> () { debug v => _1; let mut _0: (); + let mut _21: std::vec::IntoIter; let mut _22: std::vec::IntoIter; - let mut _23: std::vec::IntoIter; - let mut _24: &mut std::vec::IntoIter; - let mut _25: std::option::Option; - let mut _26: isize; - let _28: (); + let mut _23: &mut std::vec::IntoIter; + let mut _24: std::option::Option; + let mut _25: isize; + let _27: (); scope 1 { - debug iter => _23; - let _27: impl Sized; + debug iter => _22; + let _26: impl Sized; scope 2 { - debug x => _27; + debug x => _26; } } scope 3 (inlined as IntoIterator>::into_iter) { debug self => _1; - let _3: std::mem::ManuallyDrop>; - let mut _4: *const std::alloc::Global; - let mut _8: usize; - let mut _10: *mut impl Sized; - let mut _11: *const impl Sized; - let mut _12: usize; - let _29: &std::vec::Vec; - let mut _30: &std::mem::ManuallyDrop>; - let mut _31: &alloc::raw_vec::RawVec; - let mut _32: &std::mem::ManuallyDrop>; - let _33: &std::vec::Vec; - let mut _34: &std::mem::ManuallyDrop>; - let _35: &std::vec::Vec; - let mut _36: &std::mem::ManuallyDrop>; - let mut _37: &alloc::raw_vec::RawVec; - let mut _38: &std::mem::ManuallyDrop>; + let _2: std::mem::ManuallyDrop>; + let mut _3: *const std::alloc::Global; + let mut _7: usize; + let mut _9: *mut impl Sized; + let mut _10: *const impl Sized; + let mut _11: usize; + let _28: &std::vec::Vec; + let mut _29: &std::mem::ManuallyDrop>; + let mut _30: &alloc::raw_vec::RawVec; + let mut _31: &std::mem::ManuallyDrop>; + let _32: &std::vec::Vec; + let mut _33: &std::mem::ManuallyDrop>; + let _34: &std::vec::Vec; + let mut _35: &std::mem::ManuallyDrop>; + let mut _36: &alloc::raw_vec::RawVec; + let mut _37: &std::mem::ManuallyDrop>; scope 4 { - debug me => _3; + debug me => _2; scope 5 { - debug alloc => const ManuallyDrop:: {{ value: MaybeDangling::(std::alloc::Global) }}; - let _6: std::ptr::NonNull; + debug alloc => const ManuallyDrop:: {{ value: std::alloc::Global }}; + let _5: std::ptr::NonNull; scope 6 { - debug buf => _6; - let _7: *mut impl Sized; + debug buf => _5; + let _6: *mut impl Sized; scope 7 { - debug begin => _7; + debug begin => _6; scope 8 { - debug end => _11; - let _20: usize; + debug end => _10; + let _19: usize; scope 9 { - debug cap => _20; + debug cap => _19; } - scope 45 (inlined > as Deref>::deref) { - debug self => _38; - scope 46 (inlined MaybeDangling::>::as_ref) { - } - } - scope 47 (inlined alloc::raw_vec::RawVec::::capacity) { + scope 39 (inlined > as Deref>::deref) { debug self => _37; - let mut _39: &alloc::raw_vec::RawVecInner; - scope 48 (inlined std::mem::size_of::) { + } + scope 40 (inlined alloc::raw_vec::RawVec::::capacity) { + debug self => _36; + let mut _38: &alloc::raw_vec::RawVecInner; + scope 41 (inlined std::mem::size_of::) { } - scope 49 (inlined alloc::raw_vec::RawVecInner::capacity) { - debug self => _39; + scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) { + debug self => _38; debug elem_size => const ::SIZE; - let mut _21: core::num::niche_types::UsizeNoHighBit; - scope 50 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { - debug self => _21; + let mut _20: core::num::niche_types::UsizeNoHighBit; + scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { + debug self => _20; } } } } - scope 29 (inlined > as Deref>::deref) { - debug self => _34; - scope 30 (inlined MaybeDangling::>::as_ref) { - } - } - scope 31 (inlined Vec::::len) { + scope 25 (inlined > as Deref>::deref) { debug self => _33; - let mut _13: bool; - scope 32 { + } + scope 26 (inlined Vec::::len) { + debug self => _32; + let mut _12: bool; + scope 27 { } } - scope 33 (inlined std::ptr::mut_ptr::::wrapping_byte_add) { - debug self => _7; - debug count => _12; - let mut _14: *mut u8; - let mut _18: *mut u8; - let mut _19: *const impl Sized; - scope 34 (inlined std::ptr::mut_ptr::::cast::) { - debug self => _7; + scope 28 (inlined std::ptr::mut_ptr::::wrapping_byte_add) { + debug self => _6; + debug count => _11; + let mut _13: *mut u8; + let mut _17: *mut u8; + let mut _18: *const impl Sized; + scope 29 (inlined std::ptr::mut_ptr::::cast::) { + debug self => _6; } - scope 35 (inlined std::ptr::mut_ptr::::wrapping_add) { - debug self => _14; - debug count => _12; - let mut _15: isize; - scope 36 (inlined std::ptr::mut_ptr::::wrapping_offset) { - debug self => _14; - debug count => _15; + scope 30 (inlined std::ptr::mut_ptr::::wrapping_add) { + debug self => _13; + debug count => _11; + let mut _14: isize; + scope 31 (inlined std::ptr::mut_ptr::::wrapping_offset) { + debug self => _13; + debug count => _14; + let mut _15: *const u8; let mut _16: *const u8; - let mut _17: *const u8; } } - scope 37 (inlined std::ptr::mut_ptr::::with_metadata_of::) { - debug self => _18; - debug meta => _19; - scope 38 (inlined std::ptr::metadata::) { - debug ptr => _19; + scope 32 (inlined std::ptr::mut_ptr::::with_metadata_of::) { + debug self => _17; + debug meta => _18; + scope 33 (inlined std::ptr::metadata::) { + debug ptr => _18; } - scope 39 (inlined std::ptr::from_raw_parts_mut::) { + scope 34 (inlined std::ptr::from_raw_parts_mut::) { } } } - scope 40 (inlined > as Deref>::deref) { - debug self => _36; - scope 41 (inlined MaybeDangling::>::as_ref) { - } - } - scope 42 (inlined Vec::::len) { + scope 35 (inlined > as Deref>::deref) { debug self => _35; - let mut _9: bool; - scope 43 { + } + scope 36 (inlined Vec::::len) { + debug self => _34; + let mut _8: bool; + scope 37 { } } - scope 44 (inlined #[track_caller] std::ptr::mut_ptr::::add) { - debug self => _7; - debug count => _8; + scope 38 (inlined #[track_caller] std::ptr::mut_ptr::::add) { + debug self => _6; + debug count => _7; } } - scope 28 (inlined NonNull::::as_ptr) { - debug self => _6; - } - } - scope 20 (inlined > as Deref>::deref) { - debug self => _32; - scope 21 (inlined MaybeDangling::>::as_ref) { + scope 24 (inlined NonNull::::as_ptr) { + debug self => _5; } } - scope 22 (inlined alloc::raw_vec::RawVec::::non_null) { + scope 17 (inlined > as Deref>::deref) { debug self => _31; - scope 23 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _5: std::ptr::NonNull; - scope 24 (inlined std::ptr::Unique::::cast::) { - scope 25 (inlined NonNull::::cast::) { - scope 26 (inlined NonNull::::as_ptr) { + } + scope 18 (inlined alloc::raw_vec::RawVec::::non_null) { + debug self => _30; + scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _4: std::ptr::NonNull; + scope 20 (inlined std::ptr::Unique::::cast::) { + scope 21 (inlined NonNull::::cast::) { + scope 22 (inlined NonNull::::as_ptr) { } } } - scope 27 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { } } } } - scope 12 (inlined > as Deref>::deref) { - debug self => _30; - scope 13 (inlined MaybeDangling::>::as_ref) { - } - } - scope 14 (inlined Vec::::allocator) { + scope 11 (inlined > as Deref>::deref) { debug self => _29; - scope 15 (inlined alloc::raw_vec::RawVec::::allocator) { - scope 16 (inlined alloc::raw_vec::RawVecInner::allocator) { + } + scope 12 (inlined Vec::::allocator) { + debug self => _28; + scope 13 (inlined alloc::raw_vec::RawVec::::allocator) { + scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) { } } } - scope 17 (inlined #[track_caller] std::ptr::read::) { - debug src => _4; + scope 15 (inlined #[track_caller] std::ptr::read::) { + debug src => _3; } - scope 18 (inlined ManuallyDrop::::new) { + scope 16 (inlined ManuallyDrop::::new) { debug value => const std::alloc::Global; - scope 19 (inlined MaybeDangling::::new) { - } } } scope 10 (inlined ManuallyDrop::>::new) { debug value => _1; - let mut _2: std::mem::MaybeDangling>; - scope 11 (inlined MaybeDangling::>::new) { - } } } bb0: { - StorageLive(_22); - StorageLive(_11); - StorageLive(_20); - StorageLive(_5); - StorageLive(_17); - StorageLive(_3); - StorageLive(_2); - _2 = MaybeDangling::>(copy _1); - _3 = ManuallyDrop::> { value: move _2 }; - StorageDead(_2); + StorageLive(_21); + StorageLive(_10); + StorageLive(_19); StorageLive(_4); - // DBG: _30 = &_3; - // DBG: _29 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _4 = &raw const (((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); - StorageDead(_4); + StorageLive(_16); + StorageLive(_2); + _2 = ManuallyDrop::> { value: copy _1 }; + StorageLive(_3); + // DBG: _29 = &_2; + // DBG: _28 = &(_2.0: std::vec::Vec); + _3 = &raw const ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); + StorageDead(_3); + StorageLive(_5); + // DBG: _31 = &_2; + // DBG: _30 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + _4 = copy (((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _5 = copy _4 as std::ptr::NonNull (Transmute); StorageLive(_6); - // DBG: _32 = &_3; - // DBG: _31 = &(((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec); - _5 = copy ((((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _6 = copy _5 as std::ptr::NonNull (Transmute); - StorageLive(_7); - _7 = copy _5 as *mut impl Sized (Transmute); + _6 = copy _4 as *mut impl Sized (Transmute); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_8); - // DBG: _36 = &_3; - // DBG: _35 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _8 = copy (((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).1: usize); StorageLive(_9); - _9 = Le(copy _8, const ::MAX_SLICE_LEN); - assume(move _9); - StorageDead(_9); - _10 = Offset(copy _7, copy _8); - _11 = copy _10 as *const impl Sized (PtrToPtr); + StorageLive(_7); + // DBG: _35 = &_2; + // DBG: _34 = &(_2.0: std::vec::Vec); + _7 = copy ((_2.0: std::vec::Vec).1: usize); + StorageLive(_8); + _8 = Le(copy _7, const ::MAX_SLICE_LEN); + assume(move _8); StorageDead(_8); - StorageDead(_10); + _9 = Offset(copy _6, copy _7); + _10 = copy _9 as *const impl Sized (PtrToPtr); + StorageDead(_7); + StorageDead(_9); goto -> bb4; } bb2: { + StorageLive(_11); + // DBG: _33 = &_2; + // DBG: _32 = &(_2.0: std::vec::Vec); + _11 = copy ((_2.0: std::vec::Vec).1: usize); StorageLive(_12); - // DBG: _34 = &_3; - // DBG: _33 = &((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec); - _12 = copy (((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).1: usize); + _12 = Le(copy _11, const ::MAX_SLICE_LEN); + assume(move _12); + StorageDead(_12); + StorageLive(_17); StorageLive(_13); - _13 = Le(copy _12, const ::MAX_SLICE_LEN); - assume(move _13); - StorageDead(_13); - StorageLive(_18); + _13 = copy _4 as *mut u8 (Transmute); StorageLive(_14); - _14 = copy _5 as *mut u8 (Transmute); + _14 = copy _11 as isize (IntToInt); StorageLive(_15); - _15 = copy _12 as isize (IntToInt); - StorageLive(_16); - _16 = copy _5 as *const u8 (Transmute); - _17 = arith_offset::(move _16, move _15) -> [return: bb3, unwind unreachable]; + _15 = copy _4 as *const u8 (Transmute); + _16 = arith_offset::(move _15, move _14) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_16); - _18 = copy _17 as *mut u8 (PtrToPtr); StorageDead(_15); + _17 = copy _16 as *mut u8 (PtrToPtr); StorageDead(_14); - StorageLive(_19); - _19 = copy _5 as *const impl Sized (Transmute); - StorageDead(_19); + StorageDead(_13); + StorageLive(_18); + _18 = copy _4 as *const impl Sized (Transmute); StorageDead(_18); - StorageDead(_12); - _11 = copy _17 as *const impl Sized (PtrToPtr); + StorageDead(_17); + StorageDead(_11); + _10 = copy _16 as *const impl Sized (PtrToPtr); goto -> bb4; } bb4: { - // DBG: _38 = &_3; - // DBG: _37 = &(((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec); - // DBG: _39 = &((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + // DBG: _37 = &_2; + // DBG: _36 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + // DBG: _38 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); switchInt(const ::SIZE) -> [0: bb5, otherwise: bb6]; } bb5: { - _20 = const usize::MAX; + _19 = const usize::MAX; goto -> bb7; } bb6: { - StorageLive(_21); - _21 = copy (((((_3.0: std::mem::MaybeDangling>).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit); - _20 = copy _21 as usize (Transmute); - StorageDead(_21); + StorageLive(_20); + _20 = copy ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit); + _19 = copy _20 as usize (Transmute); + StorageDead(_20); goto -> bb7; } bb7: { - _22 = std::vec::IntoIter:: { buf: copy _6, phantom: const ZeroSized: PhantomData, cap: move _20, alloc: const ManuallyDrop:: {{ value: MaybeDangling::(std::alloc::Global) }}, ptr: copy _6, end: copy _11 }; - StorageDead(_7); + _21 = std::vec::IntoIter:: { buf: copy _5, phantom: const ZeroSized: PhantomData, cap: move _19, alloc: const ManuallyDrop:: {{ value: std::alloc::Global }}, ptr: copy _5, end: copy _10 }; StorageDead(_6); - StorageDead(_3); - StorageDead(_17); StorageDead(_5); - StorageDead(_20); - StorageDead(_11); - StorageLive(_23); - _23 = move _22; + StorageDead(_2); + StorageDead(_16); + StorageDead(_4); + StorageDead(_19); + StorageDead(_10); + StorageLive(_22); + _22 = move _21; goto -> bb8; } bb8: { - StorageLive(_25); StorageLive(_24); - _24 = &mut _23; - _25 = as Iterator>::next(move _24) -> [return: bb9, unwind: bb15]; + StorageLive(_23); + _23 = &mut _22; + _24 = as Iterator>::next(move _23) -> [return: bb9, unwind: bb15]; } bb9: { - _26 = discriminant(_25); - switchInt(move _26) -> [0: bb10, 1: bb12, otherwise: bb14]; + _25 = discriminant(_24); + switchInt(move _25) -> [0: bb10, 1: bb12, otherwise: bb14]; } bb10: { + StorageDead(_23); StorageDead(_24); - StorageDead(_25); - drop(_23) -> [return: bb11, unwind continue]; + drop(_22) -> [return: bb11, unwind continue]; } bb11: { - StorageDead(_23); StorageDead(_22); + StorageDead(_21); return; } bb12: { - StorageLive(_27); - _27 = move ((_25 as Some).0: impl Sized); - _28 = opaque::(move _27) -> [return: bb13, unwind: bb15]; + StorageLive(_26); + _26 = move ((_24 as Some).0: impl Sized); + _27 = opaque::(move _26) -> [return: bb13, unwind: bb15]; } bb13: { - StorageDead(_27); + StorageDead(_26); + StorageDead(_23); StorageDead(_24); - StorageDead(_25); goto -> bb8; } @@ -332,7 +314,7 @@ fn vec_move(_1: Vec) -> () { } bb15 (cleanup): { - drop(_23) -> [return: bb16, unwind terminate(cleanup)]; + drop(_22) -> [return: bb16, unwind terminate(cleanup)]; } bb16 (cleanup): { diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index 90381a12bbd4b..775f683a8f926 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -7,8 +7,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes -print-type-size field `.0`: 3077 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3077 bytes print-type-size field `.uninit`: 0 bytes @@ -38,8 +36,6 @@ print-type-size variant `Panicked`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes -print-type-size field `.0`: 1025 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes @@ -93,10 +89,6 @@ print-type-size type: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 byte print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeDangling`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index f65c5c1a7cb78..b6051da95ca42 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -7,8 +7,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes -print-type-size field `.0`: 3075 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3075 bytes print-type-size field `.uninit`: 0 bytes @@ -26,8 +24,6 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes -print-type-size field `.0`: 2050 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 2050 bytes print-type-size field `.uninit`: 0 bytes @@ -45,8 +41,6 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes -print-type-size field `.0`: 1025 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index c068818fdc9a5..0499531158844 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -12,8 +12,6 @@ print-type-size variant `Panicked`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `std::mem::MaybeDangling<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes -print-type-size field `.0`: 8192 bytes print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes @@ -53,8 +51,6 @@ print-type-size type: `std::ptr::NonNull>`: 8 bytes, alig print-type-size field `.pointer`: 8 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeDangling<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout index b51beb514ba80..4ce1ce46f6e82 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout @@ -11,8 +11,6 @@ print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes print-type-size type: `std::mem::ManuallyDrop`: 4 bytes, alignment: 4 bytes print-type-size field `.value`: 4 bytes -print-type-size type: `std::mem::MaybeDangling`: 4 bytes, alignment: 4 bytes -print-type-size field `.0`: 4 bytes print-type-size type: `std::mem::MaybeUninit`: 4 bytes, alignment: 4 bytes print-type-size variant `MaybeUninit`: 4 bytes print-type-size field `.uninit`: 0 bytes From 4de09553f59eae9f1bde2e54fa34ab23a77f954a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 12:47:05 +0200 Subject: [PATCH 3/4] remove no-longer-needed MaybeDangling from thread spawning --- library/std/src/thread/lifecycle.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/std/src/thread/lifecycle.rs b/library/std/src/thread/lifecycle.rs index d3a97bbf08fa2..11ab2190c5444 100644 --- a/library/std/src/thread/lifecycle.rs +++ b/library/std/src/thread/lifecycle.rs @@ -7,7 +7,6 @@ use super::thread::Thread; use super::{Result, spawnhook}; use crate::cell::UnsafeCell; use crate::marker::PhantomData; -use crate::mem::MaybeDangling; use crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::{AsInner, IntoInner, thread as imp}; @@ -57,14 +56,9 @@ where Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None), _marker: PhantomData }); let their_packet = my_packet.clone(); - // Pass `f` in `MaybeDangling` because actually that closure might *run longer than the lifetime of `F`*. - // See for more details. - let f = MaybeDangling::new(f); - // The entrypoint of the Rust thread, after platform-specific thread // initialization is done. let rust_start = move || { - let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.inherit_and_run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) From 903b6d300609c96a0c651569d29250ab7c6bc629 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2026 10:59:10 +0200 Subject: [PATCH 4/4] add another movable-generator regression test --- src/tools/miri/tests/pass/generators.rs | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tools/miri/tests/pass/generators.rs b/src/tools/miri/tests/pass/generators.rs index 67a169bcfe821..c5ab3fcb8e28f 100644 --- a/src/tools/miri/tests/pass/generators.rs +++ b/src/tools/miri/tests/pass/generators.rs @@ -1,10 +1,15 @@ //@edition: 2024 +//@revisions: stack tree tree_implicit_writes +//@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes +//@[tree]compile-flags: -Zmiri-tree-borrows + #![feature(gen_blocks)] fn main() { basic(); iterate(); movable_gen(); + movable_gen2(); } fn basic() { @@ -78,3 +83,33 @@ pub fn movable_gen() { let mut j = i; assert_eq!(j.next(), None); } + +/// Regression test for . +fn movable_gen2() { + // a struct that has a drop flag and contains a reference + struct DropMut(&'static mut T); + impl Drop for DropMut { + fn drop(&mut self) { + drop(unsafe { Box::from_raw(self.0) }); + } + } + + let mut a = gen { + let b = DropMut(Box::leak(Box::new(1))); + + // create a drop flag on `b` + let c; + if true { + c = b; // and ensure it's set to false + } else { + c = DropMut(Box::leak(Box::new(2))); + } + + *c.0 = 3; + 4.yield; + *c.0 = 5; + }; + let _ = a.next(); + let mut d = a; + let _ = d.next(); +}