or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
xxxxxxxxxx
unsafe_pinned
unsafe_pinned
Summary
Add a type
UnsafePinned
that indicates to the compiler that this field is "pinned" and there might be pointers elsewhere that point to the same memory. This means, in particular, that&mut UnsafePinned
is not necessarily a unique pointer, and thus the compiler cannot just make aliasing assumptions. However,&mut UnsafePinned
can still bemem::swap
ed, so this is not a free ticket for arbitrary aliasing of mutable references. You need to use mechanisms such asPin
to ensure that mutable references cannot be used in incorrect ways by clients.This type is then used in generator lowering, finally fixing #63818.
Motivation
Let's say you want to write a type with a self-referential pointer:
This kind of code is implicitly generated by rustc all the time when an
async fn
has a local variable of reference type that is live across a yield point. The problem is that this code has UB under our aliasing rules: the&mut S
inside theself
argument ofget_data
aliases withptr_to_data
! (If you run this code in Miri, remove theimpl !Unpin
to see the UB. Miri treatsUnpin
as magic as otherwise the entire async ecosystem would cause errors. But that is not howUnpin
was actually designed.)This simple code only has UB under Stacked Borrows but not under the LLVM aliasing rules; more complex variants of this – still in the realm of what
async fn
generates – also have UB under the LLVM aliasing rules.A more complex variant
The following roughly corresponds to a generator with this code:
When implemented by hand, it looks as follows, and causes aliasing issues:
Beyond self-referential types, a similar problem also comes up with intrusive linked lists: the nodes of such a list often live on the stack frames of the functions participating in the list, but also have incoming pointers from other list elements. When a function takes a mutable reference to its stack-allocated node, that will alias the pointers from the neighboring elements. This is an example of an intrusive list in the standard library that is breaking Rust's aliasing rules.
Pin
is sometimes used to ensure that the list elements don't just move elsewhere (which would invalidate those incoming pointers) and provide a safe API, but there still is the problem that an&mut Node
is actually not a unique pointer due to these aliases – so we need a way for the to opt-out of the aliasing rules.The goal of this RFC is to offer a way of writing such self-referential types and intrusive collections without UB. We don't want to change the rules for mutable references in general (that would also affect all the code that doesn't do anything self-referential), instad we want to be able to tell the compiler that this code is doing funky aliasing and that should be taken into account for optimizations.
Guide-level explanation
To write this code in a UB-free way, wrap the fields that are targets of self-referential pointers in an
UnsafePinned
:This lets the compiler know that mutable references to
data
might still have aliases, and so optimizations cannot assume that no aliases exist. That's entirely analogous to howUnsafeCell
lets the compiler know that shared references to this field might undergo mutation.However, what is not analogous is that
&mut S
, when handed to safe code you do not control, must still be unique pointers! This is because of methods likemem::swap
that can still assume that their two arguments are non-overlapping. (mem::swap
on two&mut UnsafePinned<i32>
may soundly assume that they do not alias.) In other words, the safety invariant of&mut S
still requires full ownership of the entire memory rangeS
is stored at; for the duration that a function holds on to the borrow, nobody else may read and write this memory. But again, this is a safety invariant; it only applies to safe code you do not control. You can write your own code handling&mut S
and as long as that code is careful not to make use of this memory in the wrong way, potential aliasing is fine.To hand such references to safe code, use
Pin
: the typePin<&mut S>
can be safely given to external code, since thePin
wrapper blocks access to operations likemem::swap
.Similarly, the intrusive linked list from the motivation can be fixed by wrapping the entire
UnsafeListEntry
inUnsafePinned
.Reference-level explanation
API sketch:
The comment about aliasing
&mut
being "risky" refers to the fact that their safety invariant still asserts exclusive ownership. This implies thatduplicate
in the following example, while not causing immediate UB, is still unsound:The unsoundness is easily demonstrated by using safe code to cause UB:
We could even soundly make
get_mut_unchecked
return an&mut T
, given that the safety invariant is not affected byUnsafePinned
. But that would probably not be useful and only cause confusion.Here is a polyfill on current Rust that uses the
Unpin
hack to achieve mostly the same effect as this API. ("Mostly" because a safeimpl Unpin for ...
can un-do the effect of this, which would not be the case with the realUnsafePinned
.)Reference diff:
Async generator lowering changes:
UnsafePinned
.rustc and Miri changes:
UnsafeUnpin
auto trait similar toFreeze
that is implemented if the type does not contain any by-valUnsafePinned
. This trait is an internal implementation detail and (for now) not exposed to users.noalias
on mutable references is only emitted forUnsafeUnpin
types. (This replaces the current hack where it is only emitted forUnpin
types.)UnsafePinned
.SharedReadWrite
retagging insideUnsafePinned
similar to what it does insideUnsafeCell
already. (This replaces the currentUnpin
-based hack.)Comparison with some other types that affect aliasing
UnsafeCell
: disables aliasing (and affects but does not fully disable dereferenceable) behind shared refs, i.e.&UnsafeCell<T>
is special.UnsafeCell<&T>
(by-val, fully owned) is not special at all and basically like&T
;&mut UnsafeCell<T>
is also not special. Safe wrappers around this type can expose mutability behind shared references, such as&RefCell<T>
.UnsafePinned
: disables aliasing (and affects but does not fully disable dereferenceable) behind mutable refs, i.e.&mut UnsafePinned<T>
is special.UnsafePinned<&mut T>
(by-val, fully owned) is not special at all and basically like&mut T
;&UnsafePinned<T>
is also not special. Safe wrappers around this type can expose sharing that involves pinned mutable references, such asPin<&mut MyFuture>
.MaybeDangling
: disables aliasing and dereferencable of all references (and boxes) directly inside it, i.e.MaybeDangling<&[mut] T>
is special.&[mut] MaybeDangling<T>
is not special at all and basically like&[mut] T
.Drawbacks
It's yet another wrapper type adjusting our aliasing rules and very easy to mix up with
UnsafeCell
orMaybeDangling
. Furthermore, it is an extremely subtle wrapper type, as theduplicate
example shows.UnsafeUnpin
is a somewhat unfortunate twin toUnpin
. The purpose ofUnsafeUnpin
really is only to search forUnsafePinned
fields, so that we can use the trait solver to determine whether an&mut
reference getsnoalias
or not. The actual safety promise ofUnsafeUnpin
is likely going to be exactly the same asUnpin
, but we can't use a stable and safe trait to determinenoalias
:impl UnsafeUnpin for T
would add thenoalias
back to&mut T
, and that can lead to very surprising aliasing issues as thepoll_fn
debacle showed. (Note thatPollFn
has already been fixed, but that doesn't mean nobody will make similar mistakes in the future so it is worth discussing how the original, problematicPollFn
would fare under this RFC.) Splitting up the traits partially mitigates such issues: afterimpl<T> Unpin for PollFn<T>
,PollFn<T>
is (in general)Unpin + !UnsafeUnpin
. The known examples of UB that Miri found all were caused by bad aliasing assumptions, which no longer occur when the aliasing assumptions are tied toUnsafeUnpin
rather thanUnpin
. Actually moving thePollFn
would still cause problems (and that can be done in safe code since it implementsUnpin
), but now the chances of code causing UB are much reduced since one must both pin data that's moved into a closure, and move that closure – even though the Rust compiler will not help prevent such moves, programmers thinking carefully about pinning are hopefully less likely to then try to move that closure. In conclusion,Unpin + !UnsafeUnpin
types are somewhat foot-gunny but less foot-gunny than the status quo. Maybe in a future editionUnpin
can be transitioned to an unsafe trait and then this situation can be re-evaluated; for now,UnsafeUnpin
remains an unstable implementation detail similar toFreeze
. (UnsafeUnpin + !Unpin
types are harmless, one just loses the ability to callPin::deref_mut
for no good reason.)It is unfortunate that
&mut UnsafePinned
and&mut TypeThatContainsUnsafePinned
lose their no-alias assumptions even when they are not currently pinned. However, since pinning was implemented as a library concept, there's not really any way the compiler can know whether an&mut UnsafePinned
is pinned or not – working withPin<&mut TypeThatContainsUnsafePinned>
generally requires usingPin::get_unchecked_mut
andPin::map_unchecked_mut
, which exposes&mut TypeThatContainsUnsafePinned
and&mut UnsafePinned
that still need to be considered aliased.Rationale and alternatives
The proposal in this RFC matches what was discussed with the lang team a long time ago.
However, of course one could imagine alternatives:
Keep the status quo. The current sitaution is that we only make aliasing requirements on mutable references if the type they point to is
Unpin
. This is unsatisfying:Unpin
was never meant to have this job. A consequence is that a strayimpl Unpin
on aWrapper<T>
-style type can lead to subtle miscompilations since it re-adds aliasing requirements for the innerT
. Contrast this with theUnsafeCell
situation, where it is not possible for (stable) code to justimpl Freeze for T
in the wrong way –UnsafeCell
is always recognized by the compiler.On the other hand,
UnsafePinned
is rather quirky in its behavior and having two marker traits (UnsafeUnpin
andUnpin
) might be too confusing, so sticking withUnpin
might not be too bad in comparison.If we do that, however, it seems preferrable to transition
Unpin
to an unsafe trait. There is a clear statement about the types' invariants associated withUnpin
, so animpl Unpin
already comes with a proof obligation. It just happens to be the case that in a module without unsafe, one can always arrange all the pieces such that the proof obligation is satisifed. This is mostly a coincidence and related to the fact that we don't have safe field projections onPin
. That said, solving this also requires solving the trouble aroundDrop
andPin
, where effectively animpl Drop
does an implicitget_mut_unchecked
, i.e., implicitly assumes the type isUnpin
.UnsafePinned
could affect aliasing guarantees both on mutable and shared references. This would avoid the currently rather subtle situation that arises when one of many aliasing&mut UnsafePinned<T>
is cast or coerced to&UnsafePinned<T>
: that is a read-only shared reference and all aliases must stop writing! It would make this type strictly more 'powerful' thanUnsafeCell
in the sense that replacingUnsafeCell
byUnsafePinned
would always be correct. (Under the RFC as written,UnsafeCell
andUnsafePinned
can be nested to remove aliasing requirements from both shared and mutable references.)If we don't do this, we could consider removing
get
since since it seems too much like a foot-gun. But that makes shared references toUnsafePinned
fairly pointless. Shared references to generators/futures are basically useless so it is unclear what the potential use-cases here are.Instead of introducing a new type, we could say that
UnsafeCell
affects both shared and mutable references. That would lose some optimization potential on types like&mut Cell<T>
, but would avoid the footgun of coercing an&mut UnsafePinned<T>
to&UnsafePinned<T>
. That said, so far the author is not aware of Miri detecting code that would run into this footgun (and Miri is able to detect such issues).We could entirely avoid all these problems by not having aliasing restrictions on mutable references. But that is completely against the direction Rust has had for 8 years now, and it would mean removing LLVM
noalias
annotations for mutable references (and likely boxes) entirely. That is sacrificing optimization potential for the common case in favor of simplifying niche cases such as self-referential structs – which is against the usual design philosophy of Rust.Instead of adding a new type that needs to be used as
Pin<&mut UnsafePinned<T>>
, can't we just makePin<&mut T>
special? The answer is no, because working withPin<&mut T>
in unsafe code usually involves getting direct access to the&mut
and then using it "carefully". But being careful is not enough when the compiler makes non-aliasing assumptions! We need to preserve the fact that the&mut T
may have aliases even afterPin::get_unchecked_mut
was used and insidePin::map_unchecked_mut
. In a different universe where pinning is a first-class concept with native support for projections and no need forget_unchecked_mut
, this might not have been required, but with pinning being introduced as a library type, there is no (currently known) alternative toUnsafePinned
.In terms of rationale, the question that comes to mind first is why is this so different from
UnsafeCell
.UnsafeCell
opts-out of read-only guarantees for shared references, can't we just have a type that opts-out of uniqueness guarantees for mutable references? The answer is no, because mutable references have some universal operations that exploit their uniqueness – in particular,mem::swap
. In contrast, there exists no operation available on all shared references that exploits their immutability. This is why we need pinning to make APIs aroundUnsafePinned
actually sound.Naming
An earlier proposal suggested to call the type
UnsafeAliased
, since the type is not inherently tied to pinning. However, it is not possible to write sound wrappers aroundUnsafeAliased
such that we can have aliasing&mut MyType
. One has to use pinning for that:Pin<&mut MyType>
. Because of that, the RFC proposes that we suggestively put pinning into the name of the type, so that people don't confuse it with a general mechanism for aliasing mutable references. It is more like the core primitive behind pinning, where whenever a type is pinned that is caused by anUnsafePinned
field somewhere inside it.For instance, it may be tempting to use an
UnsafeAliased
type to mark a single field in some struct as "separately aliased", and then aMutex<Struct>
would acquire ownership of the entire struct except for that field. However, due tomem::swap
, that would not be sound. One cannot hand out an&mut
to such aliased memory as part of a safe-to-use abstraction – except by using pinning.Prior art
This is somewhat like
UnsafeCell
, but for mutable instead of shared references.Adding something like this to Rust has been discussed many times throughout the years. Here are some links for recent discussions:
Unresolved questions
Unpin
opting-out of aliasing guarantees to the new type? Here's a plan: define thePhantomPinned
type asUnsafePinned<()>
. Places in the standard library that useimpl !Unpin for
and the generator lowering are adjusted to useUnsafePinned
instead. Then as long as nobody outside the standard library used the unstableimpl !Unpin for
, switching thenoalias
-opt-out to theUnsafeUnpin
trait is actually backwards compatible with the (never explicitly supported)Unpin
hack! However, if we ever makeUnsafePinned
location-relevant (i.e., only data inside theUnsafePinned
is allowed to have aliases), then unsafe code in the ecosystem needs to be adjusted. The justification for this is that currently this code relies on undocumented unstable behavior (using!Unpin
to opt-out of aliasing guarantees), so we are in our right to declare it unsound. Of course we should give the ecosystem time to migrate to the new approach before we actually start doing optimizations that exploit this UB.Unpin
also affects thedereferenceable
attribute, so the same would happen for this type. Is that something we want to guarantee, or do we hope to get backdereferenceable
when better semantics for it materialize on the LLVM side?Future possibilities
&UnsafeCell<Struct>
to&UnsafeCell<Field>
, the same kind of projection could also be interesting forUnsafePinned
.Discussion
Attendance
Meeting roles
(Low priority) Naming bikeshed containment zone
Josh: This description alone already makes the name seem confusing.
UnsafePinned
indicates the field is pinned, but you need to use mechanisms such asPin
with it? What's the proposed pattern here?TC: This was originally known as
UnsafeAliased
.Josh: I saw that in the RFC thread. What was the rationale for the rename? It seems like this type is primarily about aliasing?
Ralf: There is no known way to use this type soundly in a public API without pinning.
UnsafeAliased
doesn't convey a ton of meaning (UnsafeCell
is also about aliasing), so the name was meant to help guide people in the direction of sound APIs. WithUnsafeCell
, you just have to be careful which operations you expose on&MyType
, but withUnsafePinned
things are a lot more complicated.TC: Also, RalfJ had earlier written about it:
This is also discussed in the above document here.
Josh: (Aside: Hypothetically, is it possible to have that mutability without pinning by using a relative pointer and offsetting? This is a tangent, and we probably shouldn't explore it in depth here.)
Josh: I can certainly understand "putting Pinned in the name makes it be perceived as a lot more complicated". :) More seriously, though: does
UnsafePinned
already includePin
as part of its functionality, or are you expected to pin the type containing theUnsafePinned
field??Ralf:
Pin
andUnsafePinned
are two sides of the same coin. The only way to soundly exposeUnsafePinned
types is by usingPin
, and every use ofPin
will bottom out at someUnsafePinned
somewhere that is the reason why aPin
reference is needed. You are expected to usePin
like the initial examples at the top of the document do. (I have added the full code for the fixed version of the example in the guide-level section.)Josh: Thank you for clarifying the usage and how that motivated the name. I'll think about that and try to keep the bikeshedding to a minimum. :)
Without actually suggesting an excessively awkward name here, it seems like the problem is that
UnsafePinned
is realyUnsafeNeedsPin
or similar? SinceUnsafePinned
doesn't make something pinned, it's the thing at the bottom of aPin
that's the reason whyPin
is needed.TC: Perhaps we could say that it doesn't make it pinned, but (assuming the program is correct) it is pinned.
Josh: The name still seems like it isn't helping understanding. And with pinning we could use all the help we can get on that front. In any case, let's not spend substantial meeting time on a naming bikeshed. Let's make sure we have everything else answered first.
TC: Absolutely.
Ralf: Naming is hard, yeah. I haven't yet found a name I am really happy with.
(Answered) Understanding the aliasing rules
Josh: I know that
&mut
is intended to be non-aliased. I'd assumed that meant "you can't have two&mut
pointing to the same place, or a&mut
and a&
". But it looks like the rule being used by this RFC is that you also can't have a&mut
and a*const
/*mut
pointing to the same place, as well? Has that always been the (intended) rule, and people just widely ignored it in unsafe code? Or, can you have a&mut
and a raw pointer pointing to the same place but you can't write through the raw pointer?Ralf:
&mut
having no aliases at all has always been the rule, as far as I know. It's the only way for that rule to actually be useful: if we allow aliasing an&mut
and a*mut
, then we absolutely can not usenoalias
in our LLVM codegen. The saving grace is that we allow reborrowing. So the rule is that an&mut
cannot alias any raw pointer that is not derived from it. But if you have an&mut
and then create 15 raw pointers from that, those can all alias with each other as much as they want. (Stacked Borrows wants you to not use the&mut
itself while the raw pointers are active. LLVMnoalias
and Tree Borrows do allow you to mix and match the&mut
and the*mut
derived from it. But the "derived from it" part is extremely important here.)Josh: Does "derived from it" here imply that you can't have a
&mut
and a*mut
both derived from the same T, you have to ensure that the*mut
is derived from themut
?Ralf: What is a reference "derived from a T"? References/pointers get derived from other references/pointers.
Josh: Sigh, terminology. Does "derived from it" here imply that you can't have a
&mut
and a*mut
both taken from the same T (e.g. via two separate take-the-address-of operations), you have to ensure that the*mut
is derived from themut
?Ralf:
let
-bound variables are places so they are basically pointers. Maybe you mean derived from that? (If it's not a let-bound variable then it is another pointer:&addr_of!(*x)
is derived fromx
.) Yeah I think we need a concrete code example as we don't seem to have common terms, sorry.Josh: In code:
Ralf:
p2
is not derived fromp1
and hence using both is UB (under Stacked Borrows and Tree Borrows).Josh: Got it. Whereas here:
Ralf: Yes now
p2
is derived fromp1
. (It boils down to provenance, as you will probably not be surprised to hear.)Josh: Thanks. I think this entire section is now resolved and answered. +1.
The
duplicate
examplepnkfelix: I agree the
duplicate
example is subtle. I want to double check my understanding of the statement "while not causing immediate UB, is still unsound".pnkfelix: I would have thought, intuitively, being in a state where you have a function that returns a
(&'a mut S, &'a mut S)
where the two tuple elements alias each other is a state of immediate UB.Ralf: The entire point of
UnsafePinned
is to make that not immediate UB.UnsafePinned
downgrades what would be immediate UB (violation of language/validity rules) to a violation of the safety invariant, which can lead to UB later – but that "UB later" can be avoided by using carerful abstractions such asPin
.pnkfelix: Okay. So then the only case where it is not immediate UB is when
S
has anUnsafePinned
contained (transitively) within, right?Ralf: Specifically the overlapping parts must all be in an
UnsafePinned
. (And then if they are next toUnsafePinned
we enter undecided territory, similar to the discussions about the granularity ofUnsafeCell
.)pnkfelix: and the overlapping parts cannot be themselves behind some level of indirection, like a
Box
? I might need to write out an example.Ralf: Not sure I follow.
UnsafePinned
only has a by-value effect, similar toUnsafeCell
. So twoUnsafePinned<&mut T>
are not allowed to alias. An example might help :)pnkfelix: Okay yes I think that matches my understanding.
pnkfelix: I think I was going for whether this would be immediate UB:
pnkfelix: and my current understanding is that that would (still) be immediate UB.
Ralf: Yes, that would still be immediate UB.
Ergonomics of wrapper types
tmandry: General comment that even though it can be considered separately from this proposal, I would like to see us move to using field attributes eventually.
Josh: Don't we still need that represented in the type system somehow, though?
tmandry: Yeah I was looking for the gap in my thinking; that's probably it. An alternative would be "let's make newtypes less annoying to use".
Josh: +1 to that. I wonder if some kind of generalized solution to "types you can project through" would help there. (That's a tangent though.)
tmandry: But as I type this I realize that the accessors on
UnsafePinned
are in some sense the point, and a mutable reference to the underlying type is not what you want. Therefore more convenient access to the inner value is not actually desirable.scottmcm: in particular, any time
&mut s.foo
doesn't give&mut typeof(S::foo)
is pretty awkward – it can be really bad for proc macros especially, since often every such macro needs to know about the attribute specifically instead of being able to delegate to a real type.Does this close any doors or add any constraints on future possibilities for safe self-referential types?
Josh: Suppose, in the future, with some additional work on the compiler / borrow checker, someone wants to put forth a design for safe self-referential data structures, ideally one that doesn't necessarily require pinning. (e.g. references using relative pointers, or some other solution.) Does the introduction of this type close any doors on those possibilities, or substantially constrain the design of those possibilities? (This RFC does not have to solve that problem, but I'd like to understand the degree to which this RFC constrains future solutions.)
Ralf: That's hard without having an example of what that design would look like. You had earlier mentioned relative pointers. If you have those, e.g., within a struct, you can do that today.
Josh: So there are many possibilities that wouldn't intersect with this feature?
Ralf: That sounds right.
Felix's question
Ralf: E.g.:
(Felix's summary:
fn duplicate
is buggy; or at least, someone using it has to understand that they are handling nuclear waste that may violate assumptions of other code that is built upon the guarantees of&mut T
. The distinction between "immediate UB" vs "is unsound" is a matter of what we might allow, in the language, for modules/crates to use in a local, controlled manner, and not as part of a general publicly accessible API.)Adding pinning to the language
tmandry: Would this be compatible with adding pinning to the language later?
Ralf: As far as I can tell.
tmandry: It seems like we need to do this in any case.
Going through open questions
tmandry: Adding a topic to make sure we walk through all the open questions.
TC: Let's set out subsections for this.
Should this affect shared references?
Ralf: Concretely, do we want
&UnsafePinned<T>
to disable aliasing guarantees? My inclination is no, as we want orthogonal language features. So it would seem odd to tie these together, as one could simply nestUnsafePinned<UnsafeCell<T>>
. We could of course relax this later.How do we transition code that relies on Unpin opting-out of aliasing guarantees to the new type?
Unpin
opting-out of aliasing guarantees to the new type? Here's a plan: define thePhantomPinned
type asUnsafePinned<()>
. Places in the standard library that useimpl !Unpin for
and the generator lowering are adjusted to useUnsafePinned
instead. Then as long as nobody outside the standard library used the unstableimpl !Unpin for
, switching thenoalias
-opt-out to theUnsafeUnpin
trait is actually backwards compatible with the (never explicitly supported)Unpin
hack! However, if we ever makeUnsafePinned
location-relevant (i.e., only data inside theUnsafePinned
is allowed to have aliases), then unsafe code in the ecosystem needs to be adjusted. The justification for this is that currently this code relies on undocumented unstable behavior (using!Unpin
to opt-out of aliasing guarantees), so we are in our right to declare it unsound. Of course we should give the ecosystem time to migrate to the new approach before we actually start doing optimizations that exploit this UB.Ralf: For
UnsafeCell
we haveFreeze
. ForUnsafePinned
, we'd have e.g. anUnsafeUnpinned
. It'd be annoying to have bothUnsafePinned
andPinned
, but I don't see a way around it.tmandry: How widespread is it that people are relying on this? How much code would need to change if we added this rule that people needed to wrap this generator-like code in
UnsafePinned
?TC: That is already the rule in a sense; people are already doing this; it's just unsound today.
Ralf: Once we give people these tools, people will be able to fix their code. And we'll be able to see in Miri how much code blows up.
Ralf: Long term it might be good to deprecate
PhantomPinned
. If we end up with the semantics whereUnsafeUnpin
on one field doesn't affect all fields, thenPhantomPinned
is a bit of a trap.(Added later by Felix: regarding
UnsafeCell
's effects on neighboring fields, see e.g. ucg#236, and also this zulip chat on TreeBorrows.)In which module should this type live?
Josh:
std::pin
? If it's so closely tied to pinning.Ralf: That sounds reasonable.
Josh: Maybe we should bundle this with the question of the name. If it's name is tied to pin, it may make sense there.
Handling of
dereferenceable
?Next steps
TC: What are the next steps?
tmandry: It does seem we need to do this. The name did make me raise an eyebrow initially, but the explanation made sense to me. I do have concerns how we teach this.
Ralf: So do I.
pnkfelix: This makes sense to me also, as far as I understand.
Josh: I don't have any blocking concerns here either.
TC: How do we want to handle the bikeshed on the name raised by Josh?
Ralf: We could ship this on nightly of course.
Josh: +1 on shipping this in nightly. We could consider the name later.
tmandry: I'll propose FCP merge.
How do we teach this and
UnsafeCell
?tmandry: This gives me pause; I would like to imagine what explanatory text looks like that compares and contrasts these two types.
(The meeting ended here.)