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
Closed

How to extract static reference from Option? #28839

Virtlink opened this issue Oct 4, 2015 · 10 comments
Assignees
Labels
P-high High priority regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@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
Copy link
Contributor

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
Copy link
Contributor

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
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
Copy link
Member

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

@eefriedman
Copy link
Contributor

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 nikomatsakis added the regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. label Oct 5, 2015
@nikomatsakis
Copy link
Contributor

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 High priority label Oct 5, 2015
@nikomatsakis nikomatsakis self-assigned this Oct 5, 2015
@arielb1
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
Copy link
Contributor

arielb1 commented Oct 5, 2015

2be0d0a looks like the problem commit

@dotdash
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
Copy link
Contributor

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 7, 2015
bors added a commit that referenced this issue Oct 7, 2015
@steveklabnik steveklabnik added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P-high High priority regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants