-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Unsafe lifetime #1918
Unsafe lifetime #1918
Conversation
I think it's worth considering how this feature interacts with unsafe code guidelines and affects the compiler optimizations (btw, is there any way to mention all the [unsafe code/memory model] group members?). I remember that @nikomatsakis showed that I have also a few questions about the detailed design: In this code, does the let raw: *const u8;
let r = unsafe { &*raw };
let slice = unsafe { std::slice::from_raw_parts(raw, 5) }; If yes, then what about pub fn split_at_mut<'a>(&'a mut self, mid: usize) -> (&'a mut [T], &'a mut [T]) {
let copy: &mut [T] = unsafe { &mut *(self as *mut _) };
let left = &mut self[0..mid];
let right = &mut copy[mid..];
(left, right)
} And one more snippet: let uns: &'unsafe u8;
fn choose<'a>(_: &'a u8, _: &'a u8) -> &'a u8;
let x = 5;
let xref = &x; // xref: &'x u8
let r = choose(xref, uns); What's the lifetime of |
I don't think there's any need to omit dereferenceable. The use case for this is situations like Ref/rental/owning_ref where the logical lifetime is dynamic and hence can't be specified in Rust's type system, but the code ensures that the reference is valid whenever it is dereferenced at runtime. |
@krdln good food for thought. I'll ponder these some more and update my draft soon, but in the meantime, here are my initial thoughts: Per snippet 1, I'd say that, no, For snippet 2, if we assume that the input slice is explicitly of unsafe lifetime, then the compiler is free to choose any lifetime for As for the final example, the chosen lifetime should be As for optimization, I'm nowhere near an expert on this, so I'll defer to those with experience, but it seems reasonable to me that |
Add details about: * inference * coercion * drop * optimization
Added some detail about what precisely requires unsafe scope. I believe this should enable the scenarios it's intended to without any soundness holes, but it's entirely possible I've missed something. |
The previous rules were a bit too permissive and could allow some unsoundness to get through. This iteration should be more thorough.
remove confusing language
It seems like what you're looking for is closer to If a lifetime called |
This rfc is somewhat weird, but it seems pretty neat anyway. I'm slightly divided. On one side, it seems to violate the invariants of the reference type. On the other, it cannot be created safely anyway. But well, I suspect the discussion will be dominated of discussion about invariants. |
@sgrif Currently in Rust, you can easily get a reference which requires unsafe to create, but not to dereference. It's just
If you're proposing You're right that in some cases
Also, I guess there are some usecases for |
@sgrif I went back and forth a bit on whether interacting with a But yes, the driving force behind this proposal is to be able to achieve a better API in rental. Currently this is impossible because the struct members I need to store are inexpressible. If there is a simpler, more minimal feature that will allow me to solve this, I'm absolutely open to it, but this proposal is the most limited I could come up with. I didn't just propose And as a more general point, I do think it's an important ability to be able to explicitly bypass borrowck if it's absolutely necessary to do so, and it's currently not possible to do that in cases other than reference types. |
The concept of I think the real problem here is that there is no way to tell the borrow checker to just ignore For this, it would be nice to have some way of deferring struct WrappedRef<'a, T>(Ref<'a, T> where T: 'a); This is very much like the implied bounds idea (see also rust-lang/rust#20671). To an outsider, the fn new<'a, 'b, T: 'a>(r: Ref<'a, T>) -> WrappedRef<'a, T> {
WrappedRef(r) // checks to make sure T: 'a
} After that, you can transmute This can obviously allow very dangerous violations of the trait system, but that’s what you get with |
@Rufflewind That's a fascinating idea and worth exploring, but I have reservations. My primary concern is that it involves creating intermediate wrapper types for any type that needs its constraints deferred, since it can't be done generically. I'll have to think more about the implications this would have for rental and how I'd incorporate it, but on first blush it feels like it would generate awkward boilerplate that somewhat obscures the intent. Extracting the proper bounds to attach to the inner field would also be challenging and would almost certainly require a proc-macro. Although, using a proc-macro is on the roadmap anyway. Personally I feel like |
In motivation, the workaround of SelfRefStruct makes it sounds like what you want is not struct SelfRefStruct<T> {
owner: RefCell<T>,
borrower: Ref<'lifetime_of(T), T>,
} (Yes I understand that |
@kennytm That's exactly what |
@eddyb I did consider suggesting |
@eddyb I assume The lifetime_of example is different from this, it extracts the concrete lifetime upper bound of T at monomorphization time, e.g. you cannot assign a |
I would say
Whatever choice you pick, it's clear that Edit: This also becomes a problem when you have a type with multiple |
I think the idea is that 'unsafe bounds would be confined within structs
and not exposed to users, so it is unlikely that you would have them in a
function signature in the first place.
…On Mon, Feb 27, 2017 at 12:31 PM, Phil Ruffwind ***@***.***> wrote:
I would say for<'a> is clearer, because the meaning of 'unsafe can become
ambiguous/confusing in some contexts. Consider say fn(R<'unsafe>): would
that mean
- for<'a> fn(R<'a>) or
- fn(for<'a> R<'a>)?
Whatever choice you pick, it's clear that 'unsafe is inherently a less
flexible solution than just enabling for<'a> in types.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1918 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AA9A-mwKwHmhqU_Z-N07_X663n5TG3Cdks5rgzKSgaJpZM4MIGef>
.
|
That's the same for |
@krdln That's the point, it's unsafe to lift to that (always longer or equal than reality) lifetime. As for existential lifetimes, they're just as unsafe unless you can link references to their allocations. |
|
@krdln Although I think existential lifetimes are a great addition by themselves, their semantics are more like raw pointers (safe to construct, unsafe to use). In fact, I think (I personally think existential semantics are more appropriate here, as they prevent the dangerous possibility of accidental unification with |
However, they are still allowed for unbounded lifetimes.
Removed the section about general coercions into |
@Rufflewind I'm not opposed to existential semantics in principle, but I'm concerned about the practical design implications. IIRC they've been floated and postponed before, so I'm trying to avoid retreading that ground by sticking as closely to established semantics and precedent as possible. If those familiar with borrowck's implementation and the implications of existential semantics think it's doable, then I'm on board, but for now I'm trying to blaze the shortest, narrowest path to the expressiveness that I'm blocked on. |
Just as a note on the impetus behind this RFC: Just a few minutes ago I've fielded another support request for someone using one of my crates who wanted to store some of the structs it provides beside eachother in their own struct. This is currently inhibited by their lifetime parameters, and even rental can't yet solve it for that case, so my motivation remains strong. I've felt pressure and been tempted to relent and just use reference counting to eliminate the lifetime params, but I really don't want to just toss away a core benefit of rust to fix this issue. I am concerned, however, that this might be silently happening in the ecosystem already. Several APIs either provide RCed alternatives, or are simply just RCed to begin with, to avoid this issue. |
@rfcbot fcp postpone So, I think this RFC is addressing a genuine problem, but I feel like I would rather revisit this syntax when the unsafe-code-guidelines effort has progress a little further. In particular, I feel like some aspects of how unsafe code is written may change, and there may be additional semantics we would like from an I teetered a bit on this proposal, in that I also considered that it might be useful to merge the |
Team member @nikomatsakis has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Waiting for the unsafe code guidelines before stabilization is perfectly reasonable and I support that, but I have one final plea for feature gating this sooner and allowing it to evolve. The immediate use of this feature will be to prototype a better library-level solution to the self-referential struct problem, and I have a few ideas on that front that I'd like to begin exploring. At this stage I can't fully envision the implications of the API for all scenarios or how it will interact with real world codebases, and there's no way to test it currently since the implementation for the API I'd like to expose cannot be written. I'm willing to follow along with the unsafe guidelines as they evolve and ensure my solution is fully conformant, in the interest of having a viable day 1 solution at such time as whatever final semantic form stabilizes. Either way, thanks to all for the consideration and discussion of this RFC. |
I found another crate that could use this: shawshank Currently, it uses the type signature |
My first reaction is "just use My second reaction is "oh, that's kind of gross, I see what the point of this is now". |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Would it make sense to at least reserve |
@Storyyeller I thought all keywords were reserved in lifetime names, is that not the case? |
I didn't realize that. In that case, there's no problem. |
The final comment period is now complete. |
Closing as postponed. Thanks @jpernst! |
Add a new special lifetime,
'unsafe
, that implicitly satisfies any constraint, but may only be instantiated within an unsafe context. This lifetime is used in situations where the true lifetime of a value is otherwise inexpressible, and additionally serves as a warning to readers that handling of the value requires special care. As a result, unsafe code is no longer ever required to use misleading "false" or redundant lifetimes, instead clearly stating that the invariants are maintained by custom logic instead of borrowck.Rendered