Skip to content

Commit

Permalink
Rollup merge of rust-lang#57352 - arielb1:no-manual-markers, r=nikoma…
Browse files Browse the repository at this point in the history
…tsakis

forbid manually impl'ing one of an object type's marker traits

This shouldn't break compatibility for crates that do not use
`feature(optin_builtin_traits)`, because as the test shows, it is
only possible to impl a marker trait for a trait object in the crate the
marker trait is defined in, which must define
`feature(optin_builtin_traits)`.

Fixes rust-lang#56934.

r? @nikomatsakis
  • Loading branch information
Centril committed Jan 15, 2019
2 parents 7611c49 + d38a59f commit da18f47
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/librustc_typeck/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,23 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.

if let Some(principal_def_id) = data.principal_def_id() {
if !tcx.is_object_safe(principal_def_id) {
let component_def_ids = data.iter().flat_map(|predicate| {
match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id),
ty::ExistentialPredicate::AutoTrait(def_id) => Some(*def_id),
// An associated type projection necessarily comes with
// an additional `Trait` requirement.
ty::ExistentialPredicate::Projection(..) => None,
}
});

for component_def_id in component_def_ids {
if !tcx.is_object_safe(component_def_id) {
// This is an error, but it will be reported by wfcheck. Ignore it here.
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(tcx, principal_def_id);
traits::supertrait_def_ids(tcx, component_def_id);
if supertrait_def_ids.any(|d| d == trait_def_id) {
let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
struct_span_err!(tcx.sess,
Expand All @@ -193,6 +203,5 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI
}
}
}
// FIXME: also check auto-trait def-ids? (e.g. `impl Sync for Foo+Sync`)?
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![feature(optin_builtin_traits)]

// Test for issue #56934 - that it is impossible to redundantly
// implement an auto-trait for a trait object type that contains it.

// Negative impl variant.

auto trait Marker1 {}
auto trait Marker2 {}

trait Object: Marker1 {}

// A supertrait marker is illegal...
impl !Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
// ...and also a direct component.
impl !Marker2 for dyn Object + Marker2 { } //~ ERROR E0371

// But implementing a marker if it is not present is OK.
impl !Marker2 for dyn Object {} // OK

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

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

fn main() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:14:1
|
LL | impl !Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`

error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:16:1
|
LL | impl !Marker2 for dyn Object + Marker2 { } //~ ERROR E0371
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1
|
LL | impl !Send for dyn Marker2 {} //~ ERROR E0117
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference only types defined in this crate
= note: define and implement a trait or new type instead

error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)`
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1
|
LL | impl !Send for dyn Object {} //~ ERROR E0321
| ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type

error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)`
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1
|
LL | impl !Send for dyn Object + Marker2 {} //~ ERROR E0321
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type

error: aborting due to 5 previous errors

Some errors occurred: E0117, E0321, E0371.
For more information about an error, try `rustc --explain E0117`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![feature(optin_builtin_traits)]

// Test for issue #56934 - that it is impossible to redundantly
// implement an auto-trait for a trait object type that contains it.

// Positive impl variant.

auto trait Marker1 {}
auto trait Marker2 {}

trait Object: Marker1 {}

// A supertrait marker is illegal...
impl Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
// ...and also a direct component.
impl Marker2 for dyn Object + Marker2 { } //~ ERROR E0371

// But implementing a marker if it is not present is OK.
impl Marker2 for dyn Object {} // OK

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

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

fn main() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:14:1
|
LL | impl Marker1 for dyn Object + Marker2 { } //~ ERROR E0371
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`

error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:16:1
|
LL | impl Marker2 for dyn Object + Marker2 { } //~ ERROR E0371
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1
|
LL | unsafe impl Send for dyn Marker2 {} //~ ERROR E0117
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference only types defined in this crate
= note: define and implement a trait or new type instead

error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)`
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1
|
LL | unsafe impl Send for dyn Object {} //~ ERROR E0321
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type

error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)`
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1
|
LL | unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type

error: aborting due to 5 previous errors

Some errors occurred: E0117, E0321, E0371.
For more information about an error, try `rustc --explain E0117`.

0 comments on commit da18f47

Please sign in to comment.