Repository: bevyengine/bevy
File: crates/bevy_ecs/src/world/entity_access/world_mut.rs (Rust)

Code before:
            component_ids.as_slice(),
        );

        // SAFETY: We just created the bundle, and the archetype is valid, since we are in it.
        let Some(mut remover) = (unsafe {
            BundleRemover::new_with_id(self.world, location.archetype_id, bundle_id, false)
        }) else {
            return self;
        };
        // SAFETY: The remover archetype came from the passed location and the removal can not fail.
        let new_location = unsafe {
            remover.remove(
                self.entity,
                location,
                caller,
                BundleRemover::empty_pre_remove,
            )
        }
        .0;

        self.location = Some(new_location);
        self.world.flush();
        self.update_location();
        self
    }

    /// Despawns the entity without freeing it to the allocator.
    /// This returns the new [`Entity`], which you must manage.
    /// Note that this still increases the generation to differentiate different spawns of the same row.
    ///
    /// Additionally, keep in mind the limitations documented in the type-level docs.
    /// Unless you have full knowledge of this [`EntityWorldMut`]'s lifetime,
    /// you may not assume that nothing else has taken responsibility of this [`Entity`].
    /// If you are not careful, this could cause a double free.
    ///
    /// This may be later [`spawn_at`](World::spawn_at).
    /// See [`World::despawn_no_free`] for details and usage examples.
    #[track_caller]
    pub fn despawn_no_free(mut self) -> Entity {
        self.despawn_no_free_with_caller(MaybeLocation::caller());
        self.entity
    }

    /// This despawns this entity if it is currently spawned, storing the new [`EntityGeneration`](crate::entity::EntityGeneration) in [`Self::entity`] but not freeing it.
    pub(crate) fn despawn_no_free_with_caller(&mut self, caller: MaybeLocation) {
        // setup
        let Some(location) = self.location else {
            // If there is no location, we are already despawned
            return;
        };
        let archetype = &self.world.archetypes[location.archetype_id];

Review comment (bug):
How can this cause a double free?  This method consumes the `EntityWorldMut` by value, so I would think the caller *would* have full knowledge of the lifetime.  

Code after:
        };
        // SAFETY: The remover archetype came from the passed location and the removal can not fail.
        let new_location = unsafe {
            remover.remove(
                self.entity,
                location,
                caller,
                BundleRemover::empty_pre_remove,
            )
        }
        .0;

        self.location = Some(new_location);
        self.world.flush();
        self.update_location();
        self
    }

    /// Despawns the entity without freeing it to the allocator.
    /// This returns the new [`Entity`], which you must manage.
    /// Note that this still increases the generation to differentiate different spawns of the same row.
    ///
    /// Additionally, keep in mind the limitations documented in the type-level docs.
    /// Unless you have full knowledge of this [`EntityWorldMut`]'s lifetime,
    /// you may not assume that nothing else has taken responsibility of this [`Entity`].
    /// If you are not careful, this could cause a double free.
    ///
    /// This may be later [`spawn_at`](World::spawn_at).
    /// See [`World::despawn_no_free`] for details and usage examples.
    #[track_caller]
    pub fn despawn_no_free(mut self) -> Entity {
        self.despawn_no_free_with_caller(MaybeLocation::caller());
        self.entity
    }

    /// This despawns this entity if it is currently spawned, storing the new [`EntityGeneration`](crate::entity::EntityGeneration) in [`Self::entity`] but not freeing it.
    pub(crate) fn despawn_no_free_with_caller(&mut self, caller: MaybeLocation) {
        // setup
        let Some(location) = self.location else {
            // If there is no location, we are already despawned
            return;
        };
        let archetype = &self.world.archetypes[location.archetype_id];

        // SAFETY: Archetype cannot be mutably aliased by DeferredWorld
        let (archetype, mut deferred_world) = unsafe {
            let archetype: *const Archetype = archetype;
            let world = self.world.as_unsafe_world_cell();
            (&*archetype, world.into_deferred())
        };