-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Doc: MaybeUninit::assume_init_read Safety: warn on thread safety
#148398
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
Open
gksato
wants to merge
2
commits into
rust-lang:main
Choose a base branch
from
gksato:148083_maybe_uninit_read_thread_safety_doc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+42
−0
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The text after "Note that
MaybeUninit<T>isSync" gets a bit confusing because it tries to explore all the combinations of[!]Sendand[!]Sync. Instead this should only focus on the problematic combination which isT: !Send + Sync, where you need to manually ensure that you are maintaining theSendinvariants.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took time, and I finally came up with something worth consideration:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the wording I came up with. Let me know your thoughts.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first paragraph, as a whole, seems like a wonderful simplification to me. Since I love verboseness, I might add:
However I guess it depends on preference. Brevity might win. What do you think?
On the second paragraph... hmm... to me it is puzzling. It required back-tracking when I read it. I was thinking of, like,
I meant:
On the other hand, I failed to see what you meant at glance.
What do you mean by "its auto implementations"? I assume "its" points to the singular "a safe API", but "a safe API" can be a method of a type or a function in the wild... what did you intend that would have some implementations of
Send/Sync?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for losing track of this PR in the last few weeks.
What I'm trying to say in that paragraph is that if you are using a
MaybeUninit<T>internally in your code, then in the safe wrapper around theMaybeUninit<T>(i.e. your code) you need to addT: Sendbound on the methods that useassume_init_readto move a value. This essentially boils down to making sure you addT: Sendas an extra bound on any function that callsassume_init_read.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries. You all are going through a lot, I know.
I assume you mean that we must stress bounds on functions (not that impls on wrappers are never useful). It previously didn't occurred to me, but when you mention it, it is completely obvious that it is the function bounds that should come as the primary choice. I agree with that.
Whether we should remove references to impls... well, I am biased, for I love impls, because I found this issue when I was writing
TakeOnce. It deserves impl, not bounds ontake(&self), becauseTakeOnce<T>is a lock-freeMutex<Option<T>>with limited functionality.What about:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that I understand where the confusion is coming from. In your
TakeOnceexample you are adding aSyncbound, but remember that this is in addition to the implicitSyncbound onTakeOncethat comes from its field beingSync. This results inTakeOncebeingSyncwhenTis eitherSendorSync, which is not what you want.The correct approach for your example is to suppress the implicit
Syncbound by placinginnerin anUnsafeCell. Then your explicit bound will only giveSyncwhenT: Send. In a way, you can think of theUnsafeCellas allowing you to "mutate" the data by moving it, which normally requires inner mutability.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well... I'm afraid I don't think so. Manually implementing
Sync/Sendfor a type completely nullifies their default auto-implementation for it. Even if a type only wrapsSynctypes, it doesn't imply that the outer type isSyncif it has a manual implementation ofSync. Here is an illustrating example, this doesn't compile (See Playground):There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, see that the following doesn't compile, either (Playground):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it seems I was wrong about how auto-traits work.
So back to the main issue, it seems that there are several ways of handling
T: !Send + Synctypes:assume_init_readfrom function that have a mutable reference to theMaybeUninit<T>, which only requiresSend, notSync.SyncwhenT: Sendby explicitly overriding the defaultSyncimpl.MaybeUninit<T>in some form of cell, which suppresses the defaultSyncimpl. It is then up to you to decide when you want your type to beSync.T: Copy, which allows moving a value with just&Tand therefore makes theSend/Syncdistinction irrelevant.