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

Unexpected "life is too short" error #16339

Closed
kvark opened this issue Aug 8, 2014 · 5 comments
Closed

Unexpected "life is too short" error #16339

kvark opened this issue Aug 8, 2014 · 5 comments

Comments

@kvark
Copy link
Contributor

kvark commented Aug 8, 2014

The repro code:

#![feature(macro_rules)]

#[macro_export]
macro_rules! entity {
    ($($name:ident : $component:ty,)*) => {
        type IdType = u32;
        #[deriving(Clone, PartialEq, Show)]
        pub struct Id<S>(IdType);

        /// A collection of pointers to components
        pub struct Entity {
            $(
            pub $name: Option<Id<$component>>,
            )*
        }
        impl Entity {
            pub fn new() -> Entity {
                Entity {
                    $(
                    $name: None,
                    )*
                }
            }
        }

        /// A collection of component arrays
        pub struct DataHub {
            $(
            pub $name: Vec<$component>,
            )*
        }

        /// Component change() wrapper
        pub struct Changer<'a> {
            entity: &'a Entity,
            hub: &'a mut DataHub,
        }
        impl <'a> Changer<'a> {
            $(
            pub fn $name(&mut self) -> Option<&mut $component> {
                self.entity.$name.map(|Id(id)| self.hub.$name.get_mut(id as uint))
            }
            )*
        }
    }
}

pub mod test {
    type DummyComponent = int;
    entity! {
        dummy : DummyComponent,
    }
}

fn main() {
}

Rust complains:

<anon>:41:48: 41:62 error: lifetime of `self` is too short to guarantee its contents can be safely reborrowed
<anon>:41                 self.entity.$name.map(|Id(id)| self.hub.$name.get_mut(id as uint))
                                                         ^~~~~~~~~~~~~~
<anon>:4:1: 46:2 note: in expansion of entity!
<anon>:50:5: 52:6 note: expansion site
<anon>:40:64: 42:14 note: `self` would have to be valid for the anonymous lifetime #1 defined on the block at 40:63...
<anon>:40             pub fn $name(&mut self) -> Option<&mut $component> {
<anon>:41                 self.entity.$name.map(|Id(id)| self.hub.$name.get_mut(id as uint))
<anon>:42             }
<anon>:41:17: 41:83 note: ...but `self` is only valid for the method call at 41:16
<anon>:41                 self.entity.$name.map(|Id(id)| self.hub.$name.get_mut(id as uint))
                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:4:1: 46:2 note: in expansion of entity!
@kvark
Copy link
Contributor Author

kvark commented Aug 8, 2014

Adding @nikomatsakis, @zwarich, @pnkfelix, as per @cmr request.

@huonw
Copy link
Member

huonw commented Aug 8, 2014

Minimal example:

fn small(x: &mut ()) -> &mut () {
    (|| &mut *x)()
}


fn main() { }

(At the very least, expanding the macro will make handling this issue nicer.)

@pnkfelix
Copy link
Member

pnkfelix commented Aug 8, 2014

I find it helpful to also make the lifetimes more explicit, where we can:

fn small<'a>(x: &'a mut ()) -> &'a mut () {
    let f = || &mut *x;
    f()
}

fn main() { }

since now at least one of the error messages are written in terms of 'a instead of anonymous lifetimes of various spans.

@nikomatsakis
Copy link
Contributor

I believe this error message is correct. The problem is that the closure has a lifetime tied to the stack frame where it was created -- it is not allowed to create mutable aliases of x longer than that lifetime. To really do what you want, you would have to move the variable x into the closure and then return it by moving out. But that is not possible with the current closure design (it will be possible once unboxed closures are fully realized).

For the time being, you can work around this by using mutable options to move the value into the closure:

fn small<'a>(x: &'a mut ()) -> &'a mut () {
    let mut x = Some(x);
    let f = || {
        let x = x.take().unwrap();
        x
    };
    f()
}

fn main() { }

@nikomatsakis
Copy link
Contributor

For extra information: this situation is specific to mutable references, because we must guarantee that the mutable reference is the only reference with access to its referent. This means that they must be moved from place to place -- or reborrowed, but if they are reborrowed, it must be for a shorter duration than they were originally intended (more or less).

What happens here is that when the closure is desugared, the reference to x becomes a borrowed reference to x under the hood (let's call it b_x). And hence the code like &mut *x is desugared into &mut **b_x. The variable b_x has type &'closure mut &'a mut (), where 'closure is the lifetime of the closure. Therefore, the referent of b_x can only be reborrowed for 'closure at most, and 'closure cannot exceed the enclosing stack frame.

bors added a commit to rust-lang-ci/rust that referenced this issue Jan 15, 2024
Replace SourceRootCrates hashset output with slice for deterministic order

We only iterate over the result, and its pretty small in general so no point for the `HashSet` (additionally this way we get a more defined iteration order).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants