Skip to content

Commit 4e789e0

Browse files
committed
Remove the coherence impls pass that was specialized to builtin bounds,
since there are separate checks that apply to Copy (and Send uses the generic defaulted trait rules). Also prohibit `Sized` from being manually implemented for now.
1 parent 2e21689 commit 4e789e0

11 files changed

+184
-90
lines changed

src/librustc_typeck/coherence/impls.rs

-47
This file was deleted.

src/librustc_typeck/coherence/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ use syntax::visit;
4949
use util::nodemap::{DefIdMap, FnvHashMap};
5050
use util::ppaux::Repr;
5151

52-
mod impls;
5352
mod orphan;
5453
mod overlap;
5554
mod unsafety;
@@ -583,7 +582,6 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
583582
inference_context: new_infer_ctxt(crate_context.tcx),
584583
inherent_impls: RefCell::new(FnvHashMap()),
585584
}.check(crate_context.tcx.map.krate());
586-
impls::check(crate_context.tcx);
587585
unsafety::check(crate_context.tcx);
588586
orphan::check(crate_context.tcx);
589587
overlap::check(crate_context.tcx);

src/librustc_typeck/coherence/orphan.rs

+89-21
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
3737
a trait or new type instead");
3838
}
3939
}
40-
}
4140

42-
impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
43-
fn visit_item(&mut self, item: &ast::Item) {
41+
/// Checks exactly one impl for orphan rules and other such
42+
/// restrictions. In this fn, it can happen that multiple errors
43+
/// apply to a specific impl, so just return after reporting one
44+
/// to prevent inundating the user with a bunch of similar error
45+
/// reports.
46+
fn check_item(&self, item: &ast::Item) {
4447
let def_id = ast_util::local_def(item.id);
4548
match item.node {
4649
ast::ItemImpl(_, _, _, None, _, _) => {
@@ -63,6 +66,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
6366
span_err!(self.tcx.sess, item.span, E0118,
6467
"no base type found for inherent implementation; \
6568
implement a trait or new type instead");
69+
return;
6670
}
6771
}
6872
}
@@ -81,6 +85,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
8185
types defined in this crate; \
8286
only traits defined in the current crate can be \
8387
implemented for arbitrary types");
88+
return;
8489
}
8590
}
8691
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
@@ -90,11 +95,44 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
9095
some local type (e.g. `MyStruct<T>`); only traits defined in \
9196
the current crate can be implemented for a type parameter",
9297
param_ty.user_string(self.tcx));
98+
return;
9399
}
94100
}
95101
}
96102

97-
// Impls of a defaulted trait face additional rules.
103+
// In addition to the above rules, we restrict impls of defaulted traits
104+
// so that they can only be implemented on structs/enums. To see why this
105+
// restriction exists, consider the following example (#22978). Imagine
106+
// that crate A defines a defaulted trait `Foo` and a fn that operates
107+
// on pairs of types:
108+
//
109+
// ```
110+
// // Crate A
111+
// trait Foo { }
112+
// impl Foo for .. { }
113+
// fn two_foos<A:Foo,B:Foo>(..) {
114+
// one_foo::<(A,B)>(..)
115+
// }
116+
// fn one_foo<T:Foo>(..) { .. }
117+
// ```
118+
//
119+
// This type-checks fine; in particular the fn
120+
// `two_foos` is able to conclude that `(A,B):Foo`
121+
// because `A:Foo` and `B:Foo`.
122+
//
123+
// Now imagine that crate B comes along and does the following:
124+
//
125+
// ```
126+
// struct A { }
127+
// struct B { }
128+
// impl Foo for A { }
129+
// impl Foo for B { }
130+
// impl !Send for (A, B) { }
131+
// ```
132+
//
133+
// This final impl is legal according to the orpan
134+
// rules, but it invalidates the reasoning from
135+
// `two_foos` above.
98136
debug!("trait_ref={} trait_def_id={} trait_has_default_impl={}",
99137
trait_ref.repr(self.tcx),
100138
trait_def_id.repr(self.tcx),
@@ -104,29 +142,53 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
104142
trait_def_id.krate != ast::LOCAL_CRATE
105143
{
106144
let self_ty = trait_ref.self_ty();
107-
match self_ty.sty {
108-
ty::ty_struct(self_def_id, _) | ty::ty_enum(self_def_id, _) => {
109-
// The orphan check often rules this out,
110-
// but not always. For example, the orphan
111-
// check would accept `impl Send for
112-
// Box<SomethingLocal>`, but we want to
113-
// forbid that.
114-
if self_def_id.krate != ast::LOCAL_CRATE {
115-
self.tcx.sess.span_err(
116-
item.span,
117-
"cross-crate traits with a default impl \
145+
let opt_self_def_id = match self_ty.sty {
146+
ty::ty_struct(self_def_id, _) | ty::ty_enum(self_def_id, _) =>
147+
Some(self_def_id),
148+
ty::ty_uniq(..) =>
149+
self.tcx.lang_items.owned_box(),
150+
_ =>
151+
None
152+
};
153+
154+
let msg = match opt_self_def_id {
155+
// We only want to permit structs/enums, but not *all* structs/enums.
156+
// They must be local to the current crate, so that people
157+
// can't do `unsafe impl Send for Rc<SomethingLocal>` or
158+
// `unsafe impl !Send for Box<SomethingLocalAndSend>`.
159+
Some(self_def_id) => {
160+
if self_def_id.krate == ast::LOCAL_CRATE {
161+
None
162+
} else {
163+
Some(format!(
164+
"cross-crate traits with a default impl, like `{}`, \
118165
can only be implemented for a struct/enum type \
119-
defined in the current crate");
166+
defined in the current crate",
167+
ty::item_path_str(self.tcx, trait_def_id)))
120168
}
121169
}
122170
_ => {
123-
self.tcx.sess.span_err(
124-
item.span,
125-
"cross-crate traits with a default impl \
126-
can only be implemented for a struct or enum type");
171+
Some(format!(
172+
"cross-crate traits with a default impl, like `{}`, \
173+
can only be implemented for a struct/enum type, \
174+
not `{}`",
175+
ty::item_path_str(self.tcx, trait_def_id),
176+
self_ty.user_string(self.tcx)))
127177
}
178+
};
179+
180+
if let Some(msg) = msg {
181+
span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
182+
return;
128183
}
129184
}
185+
186+
// Disallow *all* explicit impls of `Sized` for now.
187+
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
188+
span_err!(self.tcx.sess, item.span, E0322,
189+
"explicit impls for the `Sized` trait are not permitted");
190+
return;
191+
}
130192
}
131193
ast::ItemDefaultImpl(..) => {
132194
// "Trait" impl
@@ -135,14 +197,20 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
135197
if trait_ref.def_id.krate != ast::LOCAL_CRATE {
136198
span_err!(self.tcx.sess, item.span, E0318,
137199
"cannot create default implementations for traits outside the \
138-
crate they're defined in; define a new trait instead.");
200+
crate they're defined in; define a new trait instead");
201+
return;
139202
}
140203
}
141204
_ => {
142205
// Not an impl
143206
}
144207
}
208+
}
209+
}
145210

211+
impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
212+
fn visit_item(&mut self, item: &ast::Item) {
213+
self.check_item(item);
146214
visit::walk_item(self, item);
147215
}
148216
}

src/librustc_typeck/diagnostics.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ register_diagnostics! {
175175
E0250, // expected constant expr for array length
176176
E0318, // can't create default impls for traits outside their crates
177177
E0319, // trait impls for defaulted traits allowed just for structs/enums
178-
E0320 // recursive overflow during dropck
178+
E0320, // recursive overflow during dropck
179+
E0321, // extended coherence rules for defaulted traits violated
180+
E0322 // cannot implement Sized explicitly
179181
}
180182

181183
__build_diagnostic_array! { DIAGNOSTICS }

src/test/auxiliary/typeck-default-trait-impl-cross-crate-coherence-lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ use std::marker::MarkerTrait;
1515

1616
pub trait DefaultedTrait : MarkerTrait { }
1717
impl DefaultedTrait for .. { }
18+
19+
pub struct Something<T> { t: T }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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::Copy;
14+
15+
enum TestE {
16+
A
17+
}
18+
19+
struct MyType;
20+
21+
struct NotSync;
22+
impl !Sync for NotSync {}
23+
24+
impl Copy for TestE {}
25+
impl Copy for MyType {}
26+
impl Copy for (MyType, MyType) {}
27+
//~^ ERROR E0206
28+
29+
impl Copy for &'static NotSync {}
30+
//~^ ERROR E0206
31+
32+
impl Copy for [MyType] {}
33+
//~^ ERROR E0206
34+
35+
impl Copy for &'static [NotSync] {}
36+
//~^ ERROR E0206
37+
38+
fn main() {
39+
}

src/test/compile-fail/coherence-impls-builtin.rs renamed to src/test/compile-fail/coherence-impls-send.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#![feature(optin_builtin_traits)]
1212

13-
use std::marker::Send;
13+
use std::marker::Copy;
1414

1515
enum TestE {
1616
A
@@ -24,20 +24,17 @@ impl !Sync for NotSync {}
2424
unsafe impl Send for TestE {}
2525
unsafe impl Send for MyType {}
2626
unsafe impl Send for (MyType, MyType) {}
27-
//~^ ERROR builtin traits can only be implemented on structs or enums
27+
//~^ ERROR E0321
2828

2929
unsafe impl Send for &'static NotSync {}
30-
//~^ ERROR builtin traits can only be implemented on structs or enums
30+
//~^ ERROR E0321
3131

3232
unsafe impl Send for [MyType] {}
33-
//~^ ERROR builtin traits can only be implemented on structs or enums
33+
//~^ ERROR E0321
3434

3535
unsafe impl Send for &'static [NotSync] {}
36-
//~^ ERROR builtin traits can only be implemented on structs or enums
37-
//~^^ ERROR conflicting implementations for trait `core::marker::Send`
38-
39-
fn is_send<T: Send>() {}
36+
//~^ ERROR E0321
37+
//~| ERROR conflicting implementations
4038

4139
fn main() {
42-
is_send::<(MyType, TestE)>();
4340
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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::Copy;
14+
15+
enum TestE {
16+
A
17+
}
18+
19+
struct MyType;
20+
21+
struct NotSync;
22+
impl !Sync for NotSync {}
23+
24+
impl Sized for TestE {} //~ ERROR E0322
25+
impl Sized for MyType {} //~ ERROR E0322
26+
impl Sized for (MyType, MyType) {} //~ ERROR E0322
27+
impl Sized for &'static NotSync {} //~ ERROR E0322
28+
impl Sized for [MyType] {} //~ ERROR E0322
29+
//~^ ERROR E0277
30+
impl Sized for &'static [NotSync] {} //~ ERROR E0322
31+
32+
fn main() {
33+
}

src/test/compile-fail/coherence-orphan.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ use lib::TheTrait;
1919

2020
struct TheType;
2121

22-
impl TheTrait<usize> for isize { } //~ ERROR E0117
22+
impl TheTrait<usize> for isize { }
23+
//~^ ERROR E0117
2324

2425
impl TheTrait<TheType> for isize { }
2526

2627
impl TheTrait<isize> for TheType { }
2728

28-
impl !Send for Vec<isize> { } //~ ERROR E0117
29-
//~^ ERROR conflicting
29+
impl !Send for Vec<isize> { }
30+
//~^ ERROR E0117
31+
//~| ERROR E0119
3032

3133
fn main() { }

0 commit comments

Comments
 (0)