Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Bad / misleading error message with auto deref and mutable borrows of multiple fields #32930

Closed
TimNN opened this issue Apr 13, 2016 · 4 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. fixed-by-NLL Bugs fixed, but only when NLL is enabled. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@TimNN
Copy link
Contributor

TimNN commented Apr 13, 2016

Consider (playpen):

struct Foo {
    a: u32,
    b: u32,
}

struct Container {
    foo: Foo,
}

impl ::std::ops::Deref for Container {
    type Target = Foo;

    fn deref(&self) -> &Foo { &self.foo }
}

impl ::std::ops::DerefMut for Container {
    fn deref_mut(&mut self) -> &mut Foo { &mut self.foo }
}

fn main() {
    let mut c = Container { foo: Foo { a: 0, b: 0 } };

    {
        // let mut c = &mut *c; // uncomment to make it work
        let _a = &mut c.a;
        let _b = &mut c.b; // ERROR!
    }

    let mut d = Box::new(Foo { a: 0, b: 0 });

    {
        // let mut d = &mut *d; // uncomment to make it work
        let _a = &mut d.a;
        let _b = &mut d.b; // ERROR!
    }
}

Intuitively this should work since rust allows mutable borrows of disjoint fields however it does not because auto deref is involved.

The error message here is particularly bad / misleading for the Box case, in my opinion:

<anon>:34:23: 34:26 error: cannot borrow `d` (here through borrowing `d.b`) as mutable more than once at a time [E0499]
<anon>:34         let _b = &mut d.b;
                                ^~~
<anon>:34:23: 34:26 help: see the detailed explanation for E0499
<anon>:33:23: 33:26 note: previous borrow of `d` occurs here (through borrowing `d.a`); the mutable borrow prevents subsequent moves, borrows, or modification of `d` until the borrow ends
<anon>:33         let _a = &mut d.a;
                                ^~~
<anon>:35:6: 35:6 note: previous borrow ends here
<anon>:31     {
<anon>:32         // let mut d = &mut *d; // uncomment to make it work
<anon>:33         let _a = &mut d.a;
<anon>:34         let _b = &mut d.b;
<anon>:35     }

First found on reddit.

@TimNN
Copy link
Contributor Author

TimNN commented Apr 13, 2016

Related to #30104

@steveklabnik steveklabnik added the A-diagnostics Area: Messages for errors, warnings, and lints label Jul 25, 2016
@steveklabnik steveklabnik added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 25, 2017
@Pauan
Copy link

Pauan commented Apr 19, 2018

I just ran into this with RefCell + borrow_mut (which in my opinion is a common situation). Thanks a lot for the &mut *foo workaround!

@shepmaster
Copy link
Member

The original example compiles successfully with NLL 🎉 .

@estebank estebank added the fixed-by-NLL Bugs fixed, but only when NLL is enabled. label Oct 15, 2018
@pnkfelix
Copy link
Member

NLL (migrate mode) is enabled in all editions as of PR #59114. Verified that test case compiled in Nightly 2015 edition; closing as fixed.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. fixed-by-NLL Bugs fixed, but only when NLL is enabled. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants