-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
MutexGuard<T> may be Sync only if T is Sync #41624
Conversation
Also remove some unnecessary unsafe impl from the tests.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
src/libstd/sync/mutex.rs
Outdated
impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} | ||
impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { } | ||
#[stable(feature = "rust1", since = "1.18.0")] | ||
unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { } |
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.
A brief test says that this is not enough to make T: !Sync → MutexGuard<T>: !Sync
Is a non-sync marker field the best way? Then opt in to Sync for this case.
Edit: Ok, sorry, that was of course a too simple test. Seems to work
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.
So this is where I was arguing with @nikomatsakis that the current semantics for positive OIBIT impls don't make sense in terms of how they apply bounds and when, when compared with other impls.
That is, I'd expect to see these two impls:
impl<'a, T: ?Sized> !Sync for MutexGuard<'a, T> { }
unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { }
Carving out a Sync
subset out of a more general !Sync
case.
Indeed that is what a !Sync
marker field would do.
EDIT: Okay, so it's not broken but it still bugs me how it's set up.
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.
@bluss: My compile-fail test seems to indicate this works, but I have to admit I don't know enough about OIBITs to say how this is supposed to be done.
@eddyb: I was not sure if that would work; are overlapping impls handed correctly? If they do, sure, I'm happy to change this. I will then also add a test checking that MutexGuard<i32>
is 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.
It fooled me, for one. The positive impls are stable though (and the negative ones are not).
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.
@eddyb This doesn't seem to work...
error[E0119]: conflicting implementations of trait `core::marker::Sync` for type `sync::mutex::MutexGuard<'_, _>`:
--> src/libstd/sync/mutex.rs:159:1
|
157 | impl<'a, T: ?Sized> !Sync for MutexGuard<'a, T> { }
| --------------------------------------------------- first implementation here
158 | #[stable(feature = "rust1", since = "1.18.0")]
159 | unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `sync::mutex::MutexGuard<'_, _>`
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.
Do you mean "stable" as in "a stable Rust feature" or "stable" as in "preserved by more impls being added elsewhere"?
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, it doesn't, but I would expect it to be the only way to achieve this result, and this is me trying to remember @nikomatsakis about a previous discussion on the matter.
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 former, @RalfJung
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.
@eddyb I argued the same thing with @nikomatsakis at RustConf, but he demonstrated an example in which that would result in adding a non-blanket impl of a non-OIBIT being a breaking change, something we've worked very hard to avoid.
In any event we do need an RFC to revise and clarify these rules because they're currently mostly unstated.
Travis complains about the |
Thanks for catching this @RalfJung! I'm personally ahead going ahead and landing this regardless of the breakage. It's (a) a soundness fix and (b) seems unlikely to be relied upon in practice. We've got a lot of runway before this reaches stable to detect regressions and help upstream authors fix the issue. In any case cc @rust-lang/libs for the breakage aspect. For the tidy error here yeah you can just pick a new feature name that's not "rust1", and it can be something arbitrary. |
All right, I picked a new feature name ( |
@alexcrichton - I think this is ready for merge. Friendly ping to keep this on your radar. |
Ok it's been a few days so I'm going to r+, but we may still back out and determine a new strategy to land if we discover this causes a number of regressions on crater. Regardless we'll get this in somehow! @bors: r+ |
📌 Commit 23522f6 has been approved by |
Ordinarily, we would do a crater run first. But I agree this seems like quite the corner case. |
MutexGuard<T> may be Sync only if T is Sync Fixes #41622 This is a breaking change. Does that imply any further process? I am not sure whether I wrote that "compilation must fail"-test correctly, but at least it is passing here with the patch applied. Same for the `since = "1.18.0"`, I just picked it because I had to pick something.
☀️ Test successful - status-appveyor, status-travis |
I think |
That's right, this will only land with 1.19. Is that a problem? |
it's fixed in master, so nightly docs show the correct Rust 1.19 |
Ah, cool. Actually, it's fixed even in the beta: https://doc.rust-lang.org/beta/std/sync/struct.MutexGuard.html |
hmm. I disagree with this fix. |
So But, theoretically, someone could write an unsafe abstraction that isn't thread-safe in a The thought of that is rather unsettling, and one more thing to keep in mind about unsafe code. |
If you mean the fix is to add that field and leave the existing fields unchanged, I disagree. That would restrict
That's right. |
@RalfJung that is a bit weird. It does feel as if |
Yes, and I agree with that. However, |
@RalfJung right, that's what I'm thinking - this seems like a design flaw with auto traits :/ you can't have a field which isn't taken into account by auto traits. |
Would it make sense for |
Fixes #41622
This is a breaking change. Does that imply any further process?
I am not sure whether I wrote that "compilation must fail"-test correctly, but at least it is passing here with the patch applied. Same for the
since = "1.18.0"
, I just picked it because I had to pick something.