-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Implement Arc
/Rc
raw pointer conversions for ?Sized
#44073
Conversation
r? @BurntSushi (rust_highfive has picked a reviewer for you, use r? to override) |
I believe this change is totally backward compatible and it makes sense with the recently merged (It was actually a comment on another project referencing that PR which made me aware that |
cc @rust-lang/libs It seems like this is a good thing to have, but I need help reviewing the actual implementation. Could someone describe at a high level what's going on in the |
@BurntSushi: The implementation of First, the definition of
So, the implementation works like this:
All of the weird trickery is used so that the same code that does the right thing for a trait object |
This was discussed in #37197 . We didn't implement it for I'm pretty convinced at this point that the correct way to do this is to have a built-in |
cc @Amanieu (they came up with a DST |
Here's a link to my implementation for reference. It is still technically UB since it derefs an invalid pointer, but it works well enough in practice until we get proper support for |
Well, shoot. I didn't realize that getting an offset from an invalid pointer was technically a dereference and therefore undefined behavior. So, it looks like a compiler-supported |
@BurntSushi @cristicbz @rust-lang/libs any of yinz have an answer to @murarth's question? ^^ |
I'm out of depth on this one. I've assigned it to @alexcrichton |
@murarth ah yeah unfortunately I think that may still be holding this back. That being said though I don't think anything is blocking an implementation of |
@alexcrichton: I did run into a few issues trying to implement an |
That seems fine to me as an implementation detail for now, but an alternate route could be to use a custom macro like |
If using a custom AST node is more flexible, that's probably a better idea than a weird intrinsic thing. Looking back at my attempted implementation, I realize the problem I ran into: In order to have Use of So, TL;DR: I'm not familiar with how AST expressions eventually become code, but I will look into it and see what I can do. |
Yeah I think using a custom AST node should help you solve that problem, for example the Another route would be to perhaps poke around with constant evaluation with an intrinsic to try to constant evaluate the field argument and that should be able to give you a string I think? |
@alexcrichton: I've run into an issue implementing
Trying to resolve this by adding a
|
Ah unfortunately I may not be of much help there, but maybe @eddyb can help? |
You can use pointers inside an |
@eddyb: I'm not sure what you're talking about. Can you give me an example? And would it work with unsized types, e.g. |
@murarth So the second thing people usually go to when union MaybeUninitialized<T> {
value: T,
dummy: ()
}
let uninit: MaybeUninitialized<RcBox<T>> = MaybeUninitialized { dummy: () } I assume you had a solution for unsized union FatThin<T: ?Sized> {
fat: *mut T,
thin: *mut ()
}
let mut combined = FatThin { fat: ptr as *mut RcBox<T> };
combined.thin = &uninit.value as *const _ as *const ();
let base_ptr = &uninit.value as *const _ as usize;
let data_ptr = &(*combined.fat).data as *const _ as usize;
let offset = data_ptr - base_ptr; Oh, I see, writing this, OTOH, how were you going to pass the fat metadata to the compiler in an |
Manually calculating offset using |
So you wanted to implemented a safe equivalent of getting the offset by subtracting the |
If it's safe to assume now and into the foreseeable future that @alexcrichton: Would that be acceptable for the implementation of this PR? |
What I meant is more like aligning Also you could use |
Yeah, the power of two thing is what I was basing that on, but using |
This all sounds reasonable to me, thanks for the tips @eddyb! |
* Add `T: ?Sized` bound to {`Arc`,`Rc`}::{`from_raw`,`into_raw`}
@alexcrichton: Tests passed on the new implementation. |
@bors: r+ A great trick! |
📌 Commit 1cbb2b3 has been approved by |
…crichton Implement `Arc`/`Rc` raw pointer conversions for `?Sized` * Add `T: ?Sized` bound to {`Arc`,`Rc`}::{`from_raw`,`into_raw`}
⌛ Testing commit 1cbb2b3 with merge 1d2511ea0c6bd20c9f8d843dd60f4f3529b81fd3... |
…crichton Implement `Arc`/`Rc` raw pointer conversions for `?Sized` * Add `T: ?Sized` bound to {`Arc`,`Rc`}::{`from_raw`,`into_raw`}
@bors retry
|
⌛ Testing commit 1cbb2b3 with merge 278c86f8c90c8beb958003c5e3c11923357ee1e9... |
…crichton Implement `Arc`/`Rc` raw pointer conversions for `?Sized` * Add `T: ?Sized` bound to {`Arc`,`Rc`}::{`from_raw`,`into_raw`}
@bors retry
|
+ // Align the unsized value to the end of the ArcInner.
+ // Because it is ?Sized, it will always be the last field in memory.
+ let align = align_of_val(&*ptr);
+ let layout = Layout::new::<ArcInner<()>>();
+ let offset = (layout.size() + layout.padding_needed_for(align)) as isize; Hmmm, is this actually correct if |
@cristicbz a pointer to |
That's interesting... thanks for the explanation. I guess I assumed the vtable somehow implicitly expressed the offset to the unsized field, but I'd never given it much thought. |
T: ?Sized
bound to {Arc
,Rc
}::{from_raw
,into_raw
}