Skip to content

Commit a247952

Browse files
committed
Disallow impl autotrait for trait object
1 parent 19423b5 commit a247952

6 files changed

+188
-67
lines changed

compiler/rustc_data_structures/src/sync.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ cfg_if! {
3131
pub auto trait Send {}
3232
pub auto trait Sync {}
3333

34-
impl<T: ?Sized> Send for T {}
35-
impl<T: ?Sized> Sync for T {}
34+
impl<T> Send for T {}
35+
impl<T> Sync for T {}
3636

3737
#[macro_export]
3838
macro_rules! rustc_erase_owner {

compiler/rustc_hir_analysis/src/coherence/orphan.rs

+82-39
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>(
8686
// struct B { }
8787
// impl Foo for A { }
8888
// impl Foo for B { }
89-
// impl !Send for (A, B) { }
89+
// impl !Foo for (A, B) { }
9090
// ```
9191
//
9292
// This final impl is legal according to the orphan
@@ -99,50 +99,93 @@ fn do_orphan_check_impl<'tcx>(
9999
tcx.trait_is_auto(trait_def_id)
100100
);
101101

102-
if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
102+
if tcx.trait_is_auto(trait_def_id) {
103103
let self_ty = trait_ref.self_ty();
104-
let opt_self_def_id = match *self_ty.kind() {
105-
ty::Adt(self_def, _) => Some(self_def.did()),
106-
ty::Foreign(did) => Some(did),
107-
_ => None,
108-
};
104+
let self_ty_kind = self_ty.kind();
109105

110-
let msg = match opt_self_def_id {
111-
// We only want to permit nominal types, but not *all* nominal types.
112-
// They must be local to the current crate, so that people
113-
// can't do `unsafe impl Send for Rc<SomethingLocal>` or
114-
// `impl !Send for Box<SomethingLocalAndSend>`.
115-
Some(self_def_id) => {
116-
if self_def_id.is_local() {
117-
None
118-
} else {
119-
Some((
120-
format!(
121-
"cross-crate traits with a default impl, like `{}`, \
122-
can only be implemented for a struct/enum type \
123-
defined in the current crate",
124-
tcx.def_path_str(trait_def_id)
125-
),
126-
"can't implement cross-crate trait for type in another crate",
127-
))
106+
if trait_def_id.is_local() {
107+
// If the auto-trait is local, almost anything goes.
108+
//
109+
// impl MyAuto for Rc<Something> {} // okay
110+
// impl<T> !MyAuto for *const T {} // okay
111+
// impl<T> MyAuto for T {} // okay
112+
//
113+
// But there is one important exception: implementing for a trait
114+
// object is not allowed.
115+
//
116+
// impl MyAuto for dyn Trait {} // NOT OKAY
117+
// impl<T: ?Sized> MyAuto for T {} // NOT OKAY
118+
//
119+
let problematic_kind = match self_ty_kind {
120+
ty::Dynamic(..) => Some("trait object"),
121+
ty::Param(..) if !self_ty.is_sized(tcx, tcx.param_env(def_id)) => {
122+
Some("generic type")
128123
}
124+
_ => None,
125+
};
126+
127+
if let Some(problematic_kind) = problematic_kind {
128+
let msg = format!(
129+
"traits with a default impl, like `{trait}`, \
130+
cannot be implemented for {problematic_kind} `{self_ty}`",
131+
trait = tcx.def_path_str(trait_def_id),
132+
);
133+
let label = format!(
134+
"a trait object implements `{trait}` if and only if `{trait}` \
135+
is one of the trait object's trait bounds",
136+
trait = tcx.def_path_str(trait_def_id),
137+
);
138+
let reported = struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
139+
return Err(reported);
129140
}
130-
_ => Some((
131-
format!(
132-
"cross-crate traits with a default impl, like `{}`, can \
141+
} else {
142+
// If the auto-trait is not local, it must only be getting
143+
// implemented for a nominal type, and specifically one local to the
144+
// current crate.
145+
//
146+
// impl<T> Sync for MyStruct<T> {} // okay
147+
//
148+
// impl Sync for Rc<MyStruct> {} // NOT OKAY
149+
//
150+
let opt_self_def_id = match *self_ty_kind {
151+
ty::Adt(self_def, _) => Some(self_def.did()),
152+
ty::Foreign(did) => Some(did),
153+
_ => None,
154+
};
155+
156+
let msg = match opt_self_def_id {
157+
Some(self_def_id) => {
158+
if self_def_id.is_local() {
159+
None
160+
} else {
161+
Some((
162+
format!(
163+
"cross-crate traits with a default impl, like `{}`, \
164+
can only be implemented for a struct/enum type \
165+
defined in the current crate",
166+
tcx.def_path_str(trait_def_id)
167+
),
168+
"can't implement cross-crate trait for type in another crate",
169+
))
170+
}
171+
}
172+
None => Some((
173+
format!(
174+
"cross-crate traits with a default impl, like `{}`, can \
133175
only be implemented for a struct/enum type, not `{}`",
134-
tcx.def_path_str(trait_def_id),
135-
self_ty
136-
),
137-
"can't implement cross-crate trait with a default impl for \
138-
non-struct/enum type",
139-
)),
140-
};
176+
tcx.def_path_str(trait_def_id),
177+
self_ty
178+
),
179+
"can't implement cross-crate trait with a default impl for \
180+
non-struct/enum type",
181+
)),
182+
};
141183

142-
if let Some((msg, label)) = msg {
143-
let reported =
144-
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
145-
return Err(reported);
184+
if let Some((msg, label)) = msg {
185+
let reported =
186+
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
187+
return Err(reported);
188+
}
146189
}
147190
}
148191

tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,26 @@ auto trait Marker2 {}
1212
trait Object: Marker1 {}
1313

1414
// A supertrait marker is illegal...
15-
impl !Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
15+
impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
16+
//~^ ERROR 0321
1617
// ...and also a direct component.
17-
impl !Marker2 for dyn Object + Marker2 { } //~ ERROR E0371
18-
19-
// But implementing a marker if it is not present is OK.
20-
impl !Marker2 for dyn Object {} // OK
18+
impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
19+
//~^ ERROR 0321
2120

2221
// A non-principal trait-object type is orphan even in its crate.
2322
impl !Send for dyn Marker2 {} //~ ERROR E0117
2423

25-
// And impl'ing a remote marker for a local trait object is forbidden
26-
// by one of these special orphan-like rules.
24+
// Implementing a marker for a local trait object is forbidden by a special
25+
// orphan-like rule.
26+
impl !Marker2 for dyn Object {} //~ ERROR E0321
2727
impl !Send for dyn Object {} //~ ERROR E0321
2828
impl !Send for dyn Object + Marker2 {} //~ ERROR E0321
2929

30-
fn main() { }
30+
// Blanket impl that applies to dyn Object is equally problematic.
31+
auto trait Marker3 {}
32+
impl<T: ?Sized> !Marker3 for T {} //~ ERROR E0321
33+
34+
auto trait Marker4 {}
35+
impl<T> !Marker4 for T {} // okay
36+
37+
fn main() {}

tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr

+37-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
11
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
22
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
33
|
4-
LL | impl !Marker1 for dyn Object + Marker2 { }
4+
LL | impl !Marker1 for dyn Object + Marker2 {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
66

7+
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
8+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
9+
|
10+
LL | impl !Marker1 for dyn Object + Marker2 {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
|
13+
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
14+
715
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
8-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
16+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
917
|
10-
LL | impl !Marker2 for dyn Object + Marker2 { }
18+
LL | impl !Marker2 for dyn Object + Marker2 {}
1119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
1220

21+
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
22+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
23+
|
24+
LL | impl !Marker2 for dyn Object + Marker2 {}
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
28+
29+
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
30+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1
31+
|
32+
LL | impl !Marker2 for dyn Object {}
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
|
35+
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
36+
1337
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
14-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1
38+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1
1539
|
1640
LL | impl !Send for dyn Marker2 {}
1741
| ^^^^^^^^^^^^^^^-----------
@@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
3357
LL | impl !Send for dyn Object + Marker2 {}
3458
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
3559

36-
error: aborting due to 5 previous errors
60+
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
61+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1
62+
|
63+
LL | impl<T: ?Sized> !Marker3 for T {}
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
|
66+
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
67+
68+
error: aborting due to 9 previous errors
3769

3870
Some errors have detailed explanations: E0117, E0321, E0371.
3971
For more information about an error, try `rustc --explain E0117`.

tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,26 @@ auto trait Marker2 {}
1212
trait Object: Marker1 {}
1313

1414
// A supertrait marker is illegal...
15-
impl Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
15+
impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
16+
//~^ ERROR E0321
1617
// ...and also a direct component.
17-
impl Marker2 for dyn Object + Marker2 { } //~ ERROR E0371
18-
19-
// But implementing a marker if it is not present is OK.
20-
impl Marker2 for dyn Object {} // OK
18+
impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
19+
//~^ ERROR E0321
2120

2221
// A non-principal trait-object type is orphan even in its crate.
2322
unsafe impl Send for dyn Marker2 {} //~ ERROR E0117
2423

25-
// And impl'ing a remote marker for a local trait object is forbidden
26-
// by one of these special orphan-like rules.
24+
// Implementing a marker for a local trait object is forbidden by a special
25+
// orphan-like rule.
26+
impl Marker2 for dyn Object {} //~ ERROR E0321
2727
unsafe impl Send for dyn Object {} //~ ERROR E0321
2828
unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321
2929

30-
fn main() { }
30+
// Blanket impl that applies to dyn Object is equally problematic.
31+
auto trait Marker3 {}
32+
impl<T: ?Sized> Marker3 for T {} //~ ERROR E0321
33+
34+
auto trait Marker4 {}
35+
impl<T> Marker4 for T {} // okay
36+
37+
fn main() {}

tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr

+37-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
11
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
22
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
33
|
4-
LL | impl Marker1 for dyn Object + Marker2 { }
4+
LL | impl Marker1 for dyn Object + Marker2 {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
66

7+
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
8+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
9+
|
10+
LL | impl Marker1 for dyn Object + Marker2 {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
|
13+
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
14+
715
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
8-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
16+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
917
|
10-
LL | impl Marker2 for dyn Object + Marker2 { }
18+
LL | impl Marker2 for dyn Object + Marker2 {}
1119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
1220

21+
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
22+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
23+
|
24+
LL | impl Marker2 for dyn Object + Marker2 {}
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
28+
29+
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
30+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1
31+
|
32+
LL | impl Marker2 for dyn Object {}
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
|
35+
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
36+
1337
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
14-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1
38+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1
1539
|
1640
LL | unsafe impl Send for dyn Marker2 {}
1741
| ^^^^^^^^^^^^^^^^^^^^^-----------
@@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
3357
LL | unsafe impl Send for dyn Object + Marker2 {}
3458
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
3559

36-
error: aborting due to 5 previous errors
60+
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
61+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1
62+
|
63+
LL | impl<T: ?Sized> Marker3 for T {}
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
|
66+
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
67+
68+
error: aborting due to 9 previous errors
3769

3870
Some errors have detailed explanations: E0117, E0321, E0371.
3971
For more information about an error, try `rustc --explain E0117`.

0 commit comments

Comments
 (0)