Skip to content
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

Merged
merged 2 commits into from
May 3, 2017

Conversation

RalfJung
Copy link
Member

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.

Also remove some unnecessary unsafe impl from the tests.
@rust-highfive
Copy link
Collaborator

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.

@bluss bluss added relnotes Marks issues that should be documented in the release notes of the next release. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Apr 29, 2017
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> { }
Copy link
Member

@bluss bluss Apr 29, 2017

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

Copy link
Member

@eddyb eddyb Apr 29, 2017

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.

Copy link
Member Author

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.

Copy link
Member

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).

Copy link
Member Author

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<'_, _>`

Copy link
Member Author

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"?

Copy link
Member

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The former, @RalfJung

Copy link
Contributor

@withoutboats withoutboats Apr 29, 2017

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.

@RalfJung
Copy link
Member Author

Travis complains about the since value changing. I thought I'd have to change it because this is really a completely different impl than the old one.
Should I change the since to say 1.0.0?

@alexcrichton
Copy link
Member

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.

@RalfJung
Copy link
Member Author

All right, I picked a new feature name (mutexguard) and pushed that as a new commit here.

@carols10cents carols10cents added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 1, 2017
@arielb1
Copy link
Contributor

arielb1 commented May 2, 2017

@alexcrichton - I think this is ready for merge. Friendly ping to keep this on your radar.

@alexcrichton
Copy link
Member

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+

@bors
Copy link
Contributor

bors commented May 2, 2017

📌 Commit 23522f6 has been approved by alexcrichton

@alexcrichton alexcrichton added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 2, 2017
@nikomatsakis
Copy link
Contributor

Ordinarily, we would do a crater run first. But I agree this seems like quite the corner case.

@bors
Copy link
Contributor

bors commented May 3, 2017

⌛ Testing commit 23522f6 with merge 0634f0a...

bors added a commit that referenced this pull request May 3, 2017
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.
@bors
Copy link
Contributor

bors commented May 3, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing 0634f0a to master...

@bors bors merged commit 23522f6 into rust-lang:master May 3, 2017
@pmarcelll
Copy link
Contributor

I think since = "1.18.0" should be since = "1.19.0" (1.18 is already in beta).

@RalfJung
Copy link
Member Author

RalfJung commented Jun 9, 2017

That's right, this will only land with 1.19. Is that a problem?

@bluss
Copy link
Member

bluss commented Jun 9, 2017

it's fixed in master, so nightly docs show the correct Rust 1.19

@RalfJung
Copy link
Member Author

RalfJung commented Jun 9, 2017

Ah, cool. Actually, it's fixed even in the beta: https://doc.rust-lang.org/beta/std/sync/struct.MutexGuard.html

@strega-nil
Copy link
Contributor

strega-nil commented Jun 10, 2017

hmm. I disagree with this fix. MutexGuard should just own a PhantomData<&mut T>... that would fix all the problems with it, and would be more correct with other auto traits. I wish I had seen this sooner.

@eddyb
Copy link
Member

eddyb commented Jun 10, 2017

So &Mutex<T> is not enough because T: Send + !Sync is allowed in a Mutex, AFAICT.

But, theoretically, someone could write an unsafe abstraction that isn't thread-safe in a Mutex, and they might remove Sync but keep Send because passing it around as an owned value works fine.

The thought of that is rather unsettling, and one more thing to keep in mind about unsafe code.
But I am hopeful @RalfJung's and others' work on unsafe correctness will keep us safe in the future.

@RalfJung
Copy link
Member Author

hmm. I disagree with this fix. MutexGuard should just own a PhantomData<&mut T>... that would fix all the problems with it, and would be more correct with other auto traits. I wish I had seen this sooner.

If you mean the fix is to add that field and leave the existing fields unchanged, I disagree. That would restrict MutexGuard<T> to be Sync only when T is both Send and Sync, which is unnecessarily restrictive.
That said, a Mutex with a non-Send T seems like a rather pointless exercise, so maybe this doesn't matter.

So &Mutex is not enough because T: Send + !Sync is allowed in a Mutex, AFAICT.

That's right. Mutex<T> is Send + Sync when T is Send. No Sync-bound on T needed.

@strega-nil
Copy link
Contributor

@RalfJung that is a bit weird. It does feel as if MutexGuard<'a, T> should be treated exactly like an &mut T wrt auto trait impls... :/

@RalfJung
Copy link
Member Author

Yes, and I agree with that. However, MutexGuard<T> also has an &Mutex<T> field, which the auto traits also take into account, and which further restricts them.

@strega-nil
Copy link
Contributor

strega-nil commented Jun 11, 2017

@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.

@RalfJung RalfJung deleted the mutexguard-sync branch July 15, 2017 18:02
@rkjnsn
Copy link
Contributor

rkjnsn commented Jul 21, 2017

Would it make sense for MutexGuard<T> to have both PhantomData<&mut T> and the explicit implementation of Sync? The explicit Sync implementation would mean it's not overly restrictive, while the PhantomData would hopefully make sure that MutexGuard doesn't end up improperly implementing any future unsafe auto traits that may be created?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.