Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Borrow check needs to consider moves into patterns #3024

Closed
bblum opened this issue Jul 26, 2012 · 19 comments
Closed

Borrow check needs to consider moves into patterns #3024

bblum opened this issue Jul 26, 2012 · 19 comments
Assignees
Labels
A-lifetimes Area: Lifetimes / regions A-typesystem Area: The type system

Comments

@bblum
Copy link
Contributor

bblum commented Jul 26, 2012

struct Dummy {
    x: int
}

impl Dummy {
    fn new(x: int) -> Dummy {
        Dummy { x: x }
    }
}

impl Drop for Dummy {
    fn drop(&self) {
        error!("Destructor %d", self.x);
    }
}

fn welp<T>(a: ~T) -> T {
    let ~x = a;
    x
}

fn main() {
    let o = ~Dummy::new(5);
    welp(o);
}

(edit: a similar problem appears for let a@b = c; see comment below.)

@eholk
Copy link
Contributor

eholk commented Jul 26, 2012

I wonder if this is related to #2548...

@nikomatsakis
Copy link
Contributor

Interesting. There may be two bugs here. The first, I would think, is that this let assignment should not be legal. The liveness code would not ordinarily allow you to move from the inside of managed data.

The second is the dtor running twice. This program exhibits the same behavior:

class dummy { let x: int; new(x: int) { self.x = x; } drop { #error["Destructor %d", self.x]; } }

fn welp<T>(+a: ~T) -> T { 
    let ~x <- a;
    x   
}

fn main() {
    let o = ~dummy(5);
    welp(o);
}   

My guess is that the running twice part is a dup of #2548 or at least related. The other part is a shortcoming of liveness/borrowck... I'm not precisely sure where the check ought to be happening that prevents moving from the interior of a managed box, but it ought to happen somewhere. Probably borrowck since it already has the code to match up patterns and so forth.

@nikomatsakis
Copy link
Contributor

actually thinking more I think it's borrowck's responsibility to prevent moves from illegal places.

@bblum
Copy link
Contributor Author

bblum commented Jul 26, 2012

Thinking more about this, I realised you should never be able to get a noncopyable out of an @-box once it's in - it's a similar problem as option::unwrap except @-boxes always "implicitly" have a loan out on their contents.

Probably moving out of an @-box should always be illegal, and you should have to do it explicitly by copy *a instead. When let-ref appears, deconstructing by-ref should be legal again.

It's interesting that the destructor runs twice in your example - that one seems more analogous to option::unwrap; seems like that should be allowed.

Also interestingly, since let is by-copy currently, this also breaks (and is nonsense, when you think about it): let @x = a

bblum added a commit that referenced this issue Jul 26, 2012
@nikomatsakis
Copy link
Contributor

I updated the title of this bug to reflect the problem that the move into @P is permitted at all. The other bug (that the dtor runs twice) is I think a dup, as I said before.

@bblum
Copy link
Contributor Author

bblum commented Aug 3, 2012

if match is going to be copy by default, I can see the same problem trying to bind the inside of an @ in a match.

@nikomatsakis
Copy link
Contributor

preventing copies is really the job of the kind checker, but yeah we'll have to be sure and get this right. I'm sure we don't now, should open a bug on it.

@bblum
Copy link
Contributor Author

bblum commented Aug 21, 2012

let a@b = c also creates a copy of c when it shouldn't. The fix for this should be the same as for that, except in the pat_ident case instead of the pat_box case.

@bblum bblum mentioned this issue Aug 24, 2012
@bblum
Copy link
Contributor Author

bblum commented Oct 25, 2012

I suspect this bug exists with move bindings in match arms too. I think this bug should instead be titled "Patterns should never be able to move out of @-boxes".

@thestinger
Copy link
Contributor

@nikomatsakis: is this still a problem?

@graydon
Copy link
Contributor

graydon commented Mar 22, 2013

reproduced on 2013-03-22

@graydon
Copy link
Contributor

graydon commented Mar 22, 2013

non-critical for 0.6, de-milestoning

@catamorphism
Copy link
Contributor

Nominating for milestone 2, backward-compatible

@nikomatsakis
Copy link
Contributor

An update: The general approach for preventing moves in patterns has shifted a bit. In particular, we are currently detecting such moves in check_match. I am not 100% sure if this is a good idea, because it's not especially DRY, but there is a certain logic to it. In general though I believe there are problems with let patterns not being checked very thoroughly.

nikomatsakis referenced this issue in huonw/rust May 10, 2013
…ern has no moves.

This check only works for `match`s, the checks (incorrectly) do not run for patterns in
`let`s.
@huonw
Copy link
Member

huonw commented May 10, 2013

I added a test in #6385 which I had to xfail because of this.

@ghost ghost assigned nikomatsakis Jun 6, 2013
@graydon
Copy link
Contributor

graydon commented Jun 6, 2013

accepted for production-ready milestone

@graydon
Copy link
Contributor

graydon commented Jul 25, 2013

Triage: reproduced 2013-07-25, editing code to compensate for language drift.

@nikomatsakis
Copy link
Contributor

@graydon I believe this bug was fixed.

In particular:

  1. @huonw's test now reports the expected error (albeit with a slightly different error message).
  2. This test only prints "Hi" once:
struct dummy {
    x: int
}

impl Drop for dummy {
    fn drop(&self) {
        println(fmt!("Hi: %d", self.x));
    }
}

fn welp<T>(a: ~T) -> T {
    let ~x = a;
    x
}

fn main() {
    let o = ~dummy { x: 5 };
    welp(o);
}
  1. The test in the initial comment (which looks to have been updated?) only prints the destructor once.

Which test did you run? Presumably the test in the initial comment?

There are still actions required:

  1. Delete @huonw's test, which is superceded by compile-fail/borrowck-move-out-of-struct-with-dtor.rs
  2. Perhaps add the example as a test? Unfortunately, the tests in run-pass for moves are given non-helpful names like move-1 and move-2 so it's hard to tell if a test exists for this condition or not.

@pcwalton pcwalton closed this as completed Jan 9, 2014
@pcwalton
Copy link
Contributor

pcwalton commented Jan 9, 2014

Closing because this bug has long since been fixed.

bors pushed a commit to rust-lang-ci/rust that referenced this issue May 15, 2021
RalfJung pushed a commit to RalfJung/rust that referenced this issue Aug 17, 2023
llvm.prefetch is not a math function

fixes the comment in src/shims/foreign_items.rs
celinval pushed a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
Dependency upgrade resulting from `cargo update`.

Co-authored-by: tautschnig <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions A-typesystem Area: The type system
Projects
None yet
Development

No branches or pull requests

8 participants