Skip to content

Destructuring boxes into multiple mutable references seems broken #30104

Closed

Description

@ben0x539

This fails with "cannot mutably borrow more than once" errors

fn push(mut node: Box<(i32, i32)>) {
    let (ref mut left, ref mut right) = *node;
}

Same here:

fn push(mut node: Box<(i32, i32)>) {
    let box (ref mut left, ref mut right) = node;
}

This works:

fn push(mut node: Box<(i32, i32)>) {
    let (ref mut left, ref mut right) = *&mut *node;
}

This also works:

fn push(node: &mut (i32, i32)) {
    let (ref mut left, ref mut right) = *node;
}

Same behavior with structs instead of tuples. Boxes are weird, destructuring into mutable borrows is weird, so I have no idea what is going on there.

Activity

  1. jethrogb commented on Feb 16, 2016

    @jethrogb
    Contributor

    #![feature(box_patterns)]

    box pattern

    There. Now other people can find this bug.

  2. aidanhs commented on Jun 2, 2016

    @aidanhs
    Contributor

    More keywords: match, if let.
    (no, they don't work either)

    Two workarounds are to either a) use *&mut *x or b) bring std::ops::DerefMut in and use *x.deref_mut():

    use std::ops::DerefMut;
    fn main() {
        let mut x = Box::new((1, 2));
        { let (ref mut a, ref mut b) = *&mut *x; }
        { let (ref mut a, ref mut b) = *x.deref_mut(); }
    }
    
  3. jonhoo commented on Oct 31, 2017

    @jonhoo
    Contributor

    Is this a dupe of #16223?

  4. Mark-Simulacrum commented on Oct 31, 2017

    @Mark-Simulacrum
    Member

    I don't think so, but am uncertain. Might have the same underlying cause, though -- hard to tell.

  5. arielb1 commented on Oct 31, 2017

    @arielb1
    Contributor

    This is as defined by RFC rust-lang/rfcs#130

  6. jethrogb commented on Oct 31, 2017

    @jethrogb
    Contributor

    I don't fully understand it, but that RFC sounds like it was intended to make Box more like other types. This issue is pointing out a discrepancy between Box and other types.

    e.g., compare the code from the original issue with

    fn push(mut node: ::std::cell::RefMut<(i32, i32)>) {
        let (ref mut left, ref mut right) = *node;
    }

    (compiles)

    This sounds to me like Box is still getting special treatment and the RFC has not been fully implemented yet, therefore this issue should remain open.

  7. arielb1 commented on Nov 1, 2017

    @arielb1
    Contributor

    @jethrogb

    So the RFC was just poorly-defined. I think the solution to mutating in match should be able to be extended to handle this.

  8. reopened this on Nov 1, 2017
  9. shepmaster commented on May 8, 2018

    @shepmaster
    Member

    3 of these 4 cases fail with Rust 1.25.0. The good news is that with NLL, all 4 work! 🎉

    use std::ops::{Deref, DerefMut};
    
    // Fails
    fn smart_two_field(v: &mut Wrap<(i32, i32)>) {
        let _a = &mut v.0;
        let _b = &mut v.1;
    }
    
    fn smart_destructure(v: &mut Wrap<(i32, i32)>) {
        let (ref mut _head, ref mut _tail) = **v;
    }
    
    // Fails
    fn box_two_field(v: &mut Box<(i32, i32)>) {
        let _a = &mut v.0;
        let _b = &mut v.1;
    }
    
    // Fails
    fn box_destructure(v: &mut Box<(i32, i32)>) {
        let (ref mut _head, ref mut _tail) = **v;
    }
    
    // My own smart pointer
    struct Wrap<T>(T);
    
    impl<T> Deref for Wrap<T> {
        type Target = T;
        fn deref(&self) -> &T {
            &self.0
        }
    }
    
    impl<T> DerefMut for Wrap<T> {
        fn deref_mut(&mut self) -> &mut T {
            &mut self.0
        }
    }
    
    fn main() {}
  10. added
    fixed-by-NLLBugs fixed, but only when NLL is enabled.
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on May 8, 2018
  11. added a commit that references this issue on Aug 17, 2018
  12. added a commit that references this issue on Aug 17, 2018
  13. added a commit that references this issue on Mar 11, 2019
    65cb35a
  14. added 3 commits that reference this issue on Apr 22, 2019
    bf0ea60
    c21fbfe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.fixed-by-NLLBugs fixed, but only when NLL is enabled.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions