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

How to extract static reference from Option? #28839

Closed
Virtlink opened this Issue Oct 4, 2015 · 10 comments

Comments

Projects
None yet
7 participants
@Virtlink
Copy link

Virtlink commented Oct 4, 2015

I have a static Option<&'static mut Foo> and I want to get the reference out of it. I know this is unsafe, but I can't seem to be able to figure out how to do this. First I tried this:

pub trait Foo { }

static mut _foo: Option<&'static mut Foo> = None;

pub fn get_foo() -> &'static mut Foo {
    unsafe { match _foo {
            Some(x) => x,
            None => panic!(),
    } }
}

The types should match, but I understand I'm trying to move x, which gives me this error:

src/lib.rs:21:15: 21:19 error: cannot move out of static item [E0507]
src/lib.rs:21         match _foo {
                            ^~~~
src/lib.rs:22:18: 22:19 note: attempting to move value to here
src/lib.rs:22             Some(x) => x,
                               ^
src/lib.rs:22:18: 22:19 help: to prevent the move, use `ref x` or `ref mut x`
                        to capture value by reference

So then I tried to use ref mut x to get a mutable reference, followed by *x to get the object back, but that also doesn't work:

pub trait Foo { }

static mut _foo: Option<&'static mut Foo> = None;

pub fn get_foo() -> &'static mut Foo {
    unsafe { match _foo {
            Some(ref mut x) => *x,
            None => panic!(),
    } }
}
src/lib.rs:22:32: 22:34 error: cannot move out of borrowed content [E0507]
src/lib.rs:22             Some(ref mut x) => *x,
                                             ^~

Finally I tried to clone or copy the &'static mut Foo, which also failed.

How do I fix this?

I'm using Rust 1.5.0-nightly (6108e8c 2015-09-28).


P.S. While typing this post I figured I try it on the Rust Playground. It fails to compile on nightly, but succeeds on beta and stable? (I'm writing a kernel and need the nightly features.)

@eefriedman

This comment has been minimized.

Copy link
Contributor

eefriedman commented Oct 4, 2015

The following works on both stable and nightly:

use std::ptr;
pub trait Foo { }
static mut _foo: Option<&'static mut Foo> = None;
pub fn get_foo() -> &'static mut Foo {
    unsafe {
        match ptr::read(&_foo) {
            Some(x) => x,
            None => panic!(),
        }
    }
}

The nightly-only error is a consequence of #28321: a borrow of an &'static mut pointer no longer has static lifetime. Not sure this is true.

@eefriedman

This comment has been minimized.

Copy link
Contributor

eefriedman commented Oct 4, 2015

Hmm... it looks like there's a bug here, though: the following, which should be equivalent to your original testcase, works:

pub trait Foo { }

static mut _foo: Option<&'static mut Foo> = None;

pub fn get_foo() -> &'static mut Foo {
    unsafe { match _foo {
            Some(ref mut x) => &mut **x,
            None => panic!(),
    } }
}

fn main() {}
@Virtlink

This comment has been minimized.

Copy link
Author

Virtlink commented Oct 4, 2015

@eefriedman Thanks, that works! I'm using your second suggestion now.

I'm curious to know whether this is indeed a bug.

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Oct 4, 2015

@rust-lang/lang, is this a bug or not?

@steveklabnik steveklabnik added the A-lang label Oct 4, 2015

@eefriedman

This comment has been minimized.

Copy link
Contributor

eefriedman commented Oct 5, 2015

There's definitely something weird going on here, and I don't think it has anything to do with static lifetimes. Another related testcase:

pub struct Foo;
// Accepted on stable and nightly
pub fn get_foo<'a, 'b>(foo: &'a mut Option<&'b mut Foo>) -> &'a mut Foo {
    match foo {
        &mut Some(ref mut x) => *x,
        &mut None => panic!(),
    }
}
// Rejected on nightly, accepted on stable
pub fn get_foo2<'a>(foo: &'a mut Option<&'a mut Foo>) -> &'a mut Foo {
    match foo {
        &mut Some(ref mut x) => *x,
        &mut None => panic!(),
    }
}
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Oct 5, 2015

I'm not 100% sure what's going on. It seems to have to do with the coercion rules. I'm not aware that they changed recently, but I'll have to review the PRs.

triage: P-high (regression)

@rust-highfive rust-highfive added the P-high label Oct 5, 2015

@nikomatsakis nikomatsakis self-assigned this Oct 5, 2015

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 5, 2015

This works on 1.4 too, but is broken on 3e6d724 - so something recent, but not too recent.

Oddly enough,

pub fn get_foo2<'a>(foo: &'a mut Option<&'a mut Foo>) -> &'a mut Foo {
    match foo {
        &mut Some(ref mut x) => match x { x => *x },
        &mut None => panic!(),
    }
}

works.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 5, 2015

2be0d0a looks like the problem commit

@dotdash

This comment has been minimized.

Copy link
Contributor

dotdash commented Oct 5, 2015

Hmm... Interesting. I guess we could revert that change while keeping the
test as trans should handle the no-op adjustment by now. I'll try that
tomorrow.
Am 05.10.2015 19:48 schrieb "arielb1" notifications@github.com:

2be0d0a
2be0d0a
looks like the problem commit


Reply to this email directly or view it on GitHub
#28839 (comment).

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Oct 6, 2015

Ah, yes, that makes sense. I should have thought of that interaction. Sigh.

dotdash added a commit to dotdash/rust that referenced this issue Oct 6, 2015

dotdash added a commit to dotdash/rust that referenced this issue Oct 6, 2015

Manishearth added a commit to Manishearth/rust that referenced this issue Oct 7, 2015

bors added a commit that referenced this issue Oct 7, 2015

dotdash added a commit to dotdash/rust that referenced this issue Oct 7, 2015

bors added a commit that referenced this issue Oct 7, 2015

dotdash added a commit to dotdash/rust that referenced this issue Oct 7, 2015

bors added a commit that referenced this issue Oct 7, 2015

@bors bors closed this in #28873 Oct 7, 2015

@steveklabnik steveklabnik added the T-lang label Mar 24, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.