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

&5 isn't on the stack #455

Closed
steveklabnik opened this issue Feb 19, 2017 · 9 comments
Closed

&5 isn't on the stack #455

steveklabnik opened this issue Feb 19, 2017 · 9 comments
Assignees
Labels

Comments

@steveklabnik
Copy link
Member

so says @eddyb

I'm filing this here because I know the old book says this incorrectly, and I'm pretty sure the new one does too. We should investigate and fix, regardless.

https://www.reddit.com/r/rust/comments/5uypl3/let_z_42/ddyesib/?context=3&st=izdc2w0s&sh=f5e495c6

@eddyb
Copy link
Member

eddyb commented Feb 20, 2017

@eddyb
Copy link
Member

eddyb commented Feb 20, 2017

In general, mentioning the stack is a bad idea. The lack of indirection is a great concept without a good name AFAIK (e.g. the fields of the struct having the same storage as the struct itself).

But more specifically: &rvalue will create a temporary with that value and borrow that unless the conditions in the 'static rvalue promotion RFC are met, then it will be pointing to constant memory.

@carols10cents
Copy link
Member

I have no idea where either the old book or the new book says this, so i'm assigning this one to you, @steveklabnik

@carols10cents
Copy link
Member

i dont think this exists anymore, reopen and tell me where to fix what if i'm wrong :)

@ghost
Copy link

ghost commented Feb 26, 2018

First edition(F.E.) book says it here: https://github.com/rust-lang/book/blob/master/first-edition/src/lifetimes.md#in-structs
EDIT2: and here: https://github.com/rust-lang/book/blob/master/first-edition/src/lifetimes.md#impl-blocks

let y = &5; // This is the same as `let _y = 5; let y = &_y;`.

I've just stumbled upon this in this playground example - to test, switch between Debug and Release modes to see where compile fails respectively succeeds, the latter being due to this rvalue static promotion (thanks to scottmcm on irc)

In other words, that statement that F.E. makes is incorrect.

Second Edition book doesn't seem to make any such comment.

EDIT: Also, the statement (which slightly below the above quote, on the same section)

We need to ensure that any reference to a Foo cannot outlive the reference to an i32 it contains.

seems to be false when rvalue static promotion is at play.

EDIT3: EDIT4: I actually posted this edit3 as a new comment: #455 (comment)

@eddyb
Copy link
Member

eddyb commented Feb 26, 2018

That last statement is still correct: if a reference to the i32 is valid for 'static, then references to a struct containing it wouldn't be able to outlive 'static (as there is nothing longer-lived).

@carols10cents
Copy link
Member

Thanks! We're no longer actively working on the first edition, but if you send in a PR to fix the problem, we'll merge it.

@ghost
Copy link

ghost commented Feb 27, 2018

edit: nevermind

Well, there is more: in https://github.com/rust-lang/book/blob/master/first-edition/src/lifetimes.md#thinking-in-scopes

when we do x = &f.x, we make x a reference to something that’s about to go out of scope.

It is unclear what's the type of x there, since the line let x; if changed into let x: &i32; makes the whole program not compile err (edit: playground v2)! Therefore if x really is a reference, as the quote above says, it doesn't matter that f.x will go out of scope. Well, I'm starting to not understand what's going on here, to be honest...

EDIT: thanks to irc user durka42:

&f.x is an expression of type &&i32
because f.x is &i32
you annotated x as &i32, so it automatically derefs &f.x so it's as if you wrote x = *(&f.x);
but that doesn't happen with z, since its type is left to be inferred, so it becomes &&i32

EDIT2: thanks eddyb (below) I didn't notice the reply until after

@eddyb
Copy link
Member

eddyb commented Feb 27, 2018

@xftroxgpx &f.x produces &&i32 because the type of f.x is &i32 and the & expression always adds another & to the type as well. If you use let x: &&i32; you will get the intended error.

If you pick &i32 for the type of x, then the assignment coerces &&i32 to &i32 by deref coercion, i.e. it implicitly does x = &**&f.x, which is equivalent to x = &*f.x and x = f.x, in this case.
And because the &i32 is &'static i32, it doesn't matter what the scope of f is.

But if the type is &&i32, then x does point into f, so the scope of f matters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants