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

Calling a closure needs to be treated like a unique-immutable borrow #12224

Closed
nikomatsakis opened this issue Feb 13, 2014 · 6 comments · Fixed by #13686
Closed

Calling a closure needs to be treated like a unique-immutable borrow #12224

nikomatsakis opened this issue Feb 13, 2014 · 6 comments · Fixed by #13686
Labels
A-type-system Area: Type system
Milestone

Comments

@nikomatsakis
Copy link
Contributor

We made closures linear so as to help prevent recursion, but the other part of that job was never done -- invoking a closure needs to be considered a unique-immutable borrow (a handy concept brought into being, at least internally, by #6801).

The goal is to prevent a program like this from compiling:

use std::hashmap::HashMap;

type Fn<'a> = 'a ||;

fn call1(c: |Fn|) {
    c(|| {
        c(|| ());
    });
}

pub fn main() {
    println!("Hello, world!");
    let mut map = HashMap::new();
    let mut c = 0;
    call1(|f| {
            error!("Inserting");
            map.insert(22, c);
            c += 1;
            error!("Finding");
            let x = map.find(&22).unwrap();
            let y = *x;
            assert_eq!(*x, y);
            f();
            error!("Found {}", *x);
            assert_eq!(*x, y);
});
}

Part of #2202.

Nominating for 1.0 (backwards compat).

@alexcrichton
Copy link
Member

Should #7836 be closed as a dupe of this?

@nikomatsakis
Copy link
Contributor Author

Ah, I missed that issue, thanks @alexcrichton

@glaebhoerl
Copy link
Contributor

Would(n't) this fall out automatically with the "closures are trait objects" approach?

@pnkfelix
Copy link
Member

Inherits designation from #7836: P-backcompat-lang, 1.0 blocker.

@pnkfelix pnkfelix added this to the 1.0 milestone Feb 13, 2014
@nikomatsakis
Copy link
Contributor Author

@glaebhoerl yes.

@huonw
Copy link
Member

huonw commented Feb 27, 2014

Something similar (an updated version of the case of the recurring closure):

// FIXME #11211
type Closure<'a> = 'a |&R|;

struct R<'a, 'b> {
    c: &'a mut Closure<'b>
}

fn innocent_looking_victim() {
    let mut vec = ~[1, 2, 3];
    conspirator(|f| {
        if vec.len() < 100 {
            vec.push(4);
            for _ in vec.iter() {
                (*f.c)(f)
            }
        }
    })
}

fn conspirator(mut f: |&R|) {
    let r = R {c: &mut f};
    f(&r)
}

fn main() {
    innocent_looking_victim()
}

This compiles with any combination of mut's for the c: & .. |& .. R| field.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Apr 23, 2014
This alters the borrow checker's requirements on invoking closures from
requiring an immutable borrow to requiring a unique immutable borrow. This means
that it is illegal to invoke a closure through a `&` pointer because there is no
guarantee that is not aliased. This does not mean that a closure is required to
be in a mutable location, but rather a location which can be proven to be
unique (often through a mutable pointer).

For example, the following code is unsound and is no longer allowed:

    type Fn<'a> = ||:'a;

    fn call(f: |Fn|) {
        f(|| {
            f(|| {})
        });
    }

    fn main() {
        call(|a| {
            a();
        });
    }

There is no replacement for this pattern. For all closures which are stored in
structures, it was previously allowed to invoke the closure through `&self` but
it now requires invocation through `&mut self`.

The standard library has a good number of violations of this new rule, but the
fixes will be separated into multiple breaking change commits.

Closes rust-lang#12224

[breaking-change]
bors added a commit that referenced this issue Apr 23, 2014
This alters the borrow checker's requirements on invoking closures from
requiring an immutable borrow to requiring a unique immutable borrow. This means 
that it is illegal to invoke a closure through a `&` pointer because there is no 
guarantee that is not aliased. This does not mean that a closure is required to
be in a mutable location, but rather a location which can be proven to be
unique (often through a mutable pointer).
                                                                                 
For example, the following code is unsound and is no longer allowed:             
                                                                                 
    type Fn<'a> = ||:'a;                                                         
                                                                                 
    fn call(f: |Fn|) {                                                           
        f(|| {                                                                   
            f(|| {})                                                             
        });                                                                      
    }                                                                            
                                                                                 
    fn main() {                                                                  
        call(|a| {                                                               
            a();                                                                 
        });                                                                      
    }                                                                            
                                                                                 
There is no replacement for this pattern. For all closures which are stored in
structures, it was previously allowed to invoke the closure through `&self` but
it now requires invocation through `&mut self`.

The standard library has a good number of violations of this new rule, but the
fixes will be separated into multiple breaking change commits.
                                                                                 
Closes #12224
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 25, 2022
flip1995 pushed a commit to flip1995/rust that referenced this issue Feb 8, 2024
Changelog for Clippy 1.76 🐈

Roses are red,
Violets are blue,
So many cute cats,
How to choose?

---

### The cat of this release is: *Cabrel* submitted by `@daniel-g-gagnon:`

<img height=500 src="https://github.com/rust-lang/rust-clippy/assets/17087237/41aea3dc-7935-4dfe-80ff-a6efd92f76ab" alt="The cats of this Clippy release" />

The cat for the next release can be voted on: [here](https://docs.google.com/forms/d/e/1FAIpQLSfERam31AEi3_5uVsugi1-JHGF9Po1oC7OIiLs8jglprZNy_g/viewform)

The cat for the next next release can be nominated in the comments and will be voted in the next changelog PR (Submission deadline is 2024-02-06 23:59CET)

---

changelog: none
flip1995 pushed a commit to flip1995/rust that referenced this issue Feb 8, 2024
Fix release year in CHANGELOG.md

Fixes a typo in rust-lang#12224

CC: `@xFrednet` `@Manishearth`

---

changelog: none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants