Skip to content

Commit c9be60b

Browse files
committed
Check for negative impls for Send and Sync
1 parent 7f7e822 commit c9be60b

File tree

5 files changed

+87
-31
lines changed

5 files changed

+87
-31
lines changed

src/librustc/middle/traits/select.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
611611
return Ok(None);
612612
}
613613

614+
614615
// If there are *NO* candidates, that there are no impls --
615616
// that we know of, anyway. Note that in the case where there
616617
// are unbound type variables within the obligation, it might
@@ -626,6 +627,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
626627

627628
// Just one candidate left.
628629
let candidate = candidates.pop().unwrap();
630+
631+
match candidate {
632+
ImplCandidate(def_id) => {
633+
match ty::trait_impl_polarity(self.tcx(), def_id) {
634+
Some(ast::ImplPolarity::Negative) => return Err(Unimplemented),
635+
_ => {}
636+
}
637+
}
638+
_ => {}
639+
}
640+
629641
Ok(Some(candidate))
630642
}
631643

@@ -714,15 +726,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
714726
debug!("obligation self ty is {}",
715727
obligation.predicate.0.self_ty().repr(self.tcx()));
716728

717-
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
729+
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
718730

719731
try!(self.assemble_builtin_bound_candidates(ty::BoundCopy,
720732
stack,
721733
&mut candidates));
722734
}
723735
Some(bound @ ty::BoundSend) |
724736
Some(bound @ ty::BoundSync) => {
725-
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
737+
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
726738

727739
// No explicit impls were declared for this type, consider the fallback rules.
728740
if candidates.vec.is_empty() && !candidates.ambiguous {
@@ -741,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
741753
// (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
742754
try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
743755
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
744-
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
756+
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
745757
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
746758
}
747759
}
@@ -1013,9 +1025,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10131025
/// Search for impls that might apply to `obligation`.
10141026
fn assemble_candidates_from_impls(&mut self,
10151027
obligation: &TraitObligation<'tcx>,
1016-
candidate_vec: &mut Vec<SelectionCandidate<'tcx>>)
1028+
candidates: &mut SelectionCandidateSet<'tcx>)
10171029
-> Result<(), SelectionError<'tcx>>
10181030
{
1031+
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
1032+
debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx()));
1033+
10191034
let all_impls = self.all_impls(obligation.predicate.def_id());
10201035
for &impl_def_id in all_impls.iter() {
10211036
self.infcx.probe(|snapshot| {
@@ -1024,7 +1039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10241039
match self.match_impl(impl_def_id, obligation, snapshot,
10251040
&skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
10261041
Ok(_) => {
1027-
candidate_vec.push(ImplCandidate(impl_def_id));
1042+
candidates.vec.push(ImplCandidate(impl_def_id));
10281043
}
10291044
Err(()) => { }
10301045
}
@@ -2214,12 +2229,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
22142229

22152230
/// Returns set of all impls for a given trait.
22162231
fn all_impls(&self, trait_def_id: ast::DefId) -> Vec<ast::DefId> {
2217-
ty::populate_implementations_for_trait_if_necessary(self.tcx(),
2218-
trait_def_id);
2219-
match self.tcx().trait_impls.borrow().get(&trait_def_id) {
2232+
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_def_id);
2233+
2234+
let mut trait_impls = match self.tcx().trait_impls.borrow().get(&trait_def_id) {
22202235
None => Vec::new(),
22212236
Some(impls) => impls.borrow().clone()
2222-
}
2237+
};
2238+
2239+
match self.tcx().trait_negative_impls.borrow().get(&trait_def_id) {
2240+
None => {},
2241+
Some(impls) => trait_impls.push_all(impls.borrow().as_slice()),
2242+
};
2243+
2244+
trait_impls
22232245
}
22242246

22252247
fn impl_obligations(&mut self,

src/librustc_typeck/check/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20932093
{
20942094
debug!("register_predicate({})",
20952095
obligation.repr(self.tcx()));
2096-
20972096
self.inh.fulfillment_cx
20982097
.borrow_mut()
20992098
.register_predicate_obligation(self.infcx(), obligation);

src/librustc_typeck/check/wf.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,24 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
5656
ty::item_path_str(ccx.tcx, local_def(item.id)));
5757

5858
match item.node {
59-
ast::ItemImpl(..) => {
59+
/// Right now we check that every default trait implementation
60+
/// has an implementation of itself. Basically, a case like:
61+
///
62+
/// `impl Trait for T {}`
63+
///
64+
/// has a requirement of `T: Trait` which was required for default
65+
/// method implementations. Although this could be improved now that
66+
/// there's a better infrastructure in place for this, it's being left
67+
/// for a follow-up work.
68+
///
69+
/// Since there's such a requirement, we need to check *just* positive
70+
/// implementations, otherwise things like:
71+
///
72+
/// impl !Send for T {}
73+
///
74+
/// won't be allowed unless there's an *explicit* implementation of `Send`
75+
/// for `T`
76+
ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
6077
self.check_impl(item);
6178
}
6279
ast::ItemFn(..) => {

src/test/compile-fail/coherence-trait-polarity-mising-default-implementation.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(optin_builtin_traits)]
12+
13+
use std::marker::Send;
14+
15+
struct Outer<T: Send>(T);
16+
17+
struct TestType;
18+
impl !Send for TestType {}
19+
20+
struct Outer2<T>(T);
21+
22+
unsafe impl<T: Send> Sync for Outer2<T> {}
23+
24+
fn is_send<T: Send>(_: T) {}
25+
fn is_sync<T: Sync>(_: T) {}
26+
27+
fn main() {
28+
Outer(TestType);
29+
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
30+
31+
is_send(TestType);
32+
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
33+
34+
// This will complain about a missing Send impl because `Sync` is implement *just*
35+
// for T that are `Send`. Look at #20366 and #19950
36+
is_sync(Outer2(TestType));
37+
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
38+
}

0 commit comments

Comments
 (0)