diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 40c3f4047ae6e..8a8ab6ea92c48 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -592,6 +592,11 @@ fn orphan_check_trait_ref<'tcx>( ) -> Result<(), OrphanCheckErr<'tcx>> { debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); + // Allow arbitrary impls of marker traits. + if tcx.trait_def(trait_ref.def_id).is_marker { + return Ok(()); + } + if trait_ref.needs_infer() && trait_ref.needs_subst() { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 07720ba71ca95..216b8f585ab7d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -223,6 +223,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // who might care about this case, like coherence, should use // that function). if candidates.is_empty() { + // It's always possible to add a marker trait impl so + // we can never consider any `T: Marker` bound to never apply. + if self + .tcx() + .trait_def(stack.obligation.predicate.skip_binder().trait_ref.def_id) + .is_marker + { + return Ok(None); + } // If there's an error type, 'downgrade' our result from // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid // emitting additional spurious errors, since we're guaranteed diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index ec2b7c13ff33c..f38556c1d0339 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -140,9 +140,36 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { ) .emit(); } + + if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) + && tcx.trait_def(trait_ref.def_id).is_marker + { + tcx + .sess + .struct_span_err(span, "negative impls are not allowed for marker traits") + .span_note(tcx.def_ident_span(trait_ref.def_id).unwrap(), "marker trait") + .emit(); + } } (ty::ImplPolarity::Reservation, _) => { - // FIXME: what amount of WF checking do we need for reservation impls? + if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) + && tcx.trait_def(trait_ref.def_id).is_marker + { + let span = tcx + .sess + .source_map() + .guess_head_span(tcx.span_of_impl(item.def_id.to_def_id()).unwrap()); + tcx.sess + .struct_span_err( + span, + "reservation impls are not allowed for marker traits", + ) + .span_note( + tcx.def_ident_span(trait_ref.def_id).unwrap(), + "marker trait", + ) + .emit(); + } } _ => unreachable!(), } diff --git a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs index 24b878927530c..4277dd3f045cf 100644 --- a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs @@ -12,6 +12,6 @@ impl !Send for TestType {} //~ ERROR found both positive and nega unsafe impl Send for TestType {} //~ ERROR conflicting implementations -impl !Send for TestType {} +impl !Send for TestType {} //~ ERROR found both positive and negative implementation fn main() {} diff --git a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr index 5295170cd8bf3..3a30f256d1e82 100644 --- a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr +++ b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr @@ -16,7 +16,16 @@ LL | unsafe impl Send for TestType {} LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -error: aborting due to 2 previous errors +error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType`: + --> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1 + | +LL | unsafe impl Send for TestType {} + | ------------------------------------------------------ positive implementation here +... +LL | impl !Send for TestType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0119, E0751. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/negative-impl-marker-traits.rs b/src/test/ui/coherence/negative-impl-marker-traits.rs new file mode 100644 index 0000000000000..ff2ca0a5ac972 --- /dev/null +++ b/src/test/ui/coherence/negative-impl-marker-traits.rs @@ -0,0 +1,10 @@ +#![feature(marker_trait_attr, negative_impls)] +#[marker] +trait Trait {} + +impl !Trait for () {} //~ ERROR negative impls are not allowed for marker traits + +struct Local; +impl !Trait for Local {} //~ ERROR negative impls are not allowed for marker traits + +fn main() {} diff --git a/src/test/ui/coherence/negative-impl-marker-traits.stderr b/src/test/ui/coherence/negative-impl-marker-traits.stderr new file mode 100644 index 0000000000000..caf4fa7573b40 --- /dev/null +++ b/src/test/ui/coherence/negative-impl-marker-traits.stderr @@ -0,0 +1,26 @@ +error: negative impls are not allowed for marker traits + --> $DIR/negative-impl-marker-traits.rs:5:6 + | +LL | impl !Trait for () {} + | ^ + | +note: marker trait + --> $DIR/negative-impl-marker-traits.rs:3:7 + | +LL | trait Trait {} + | ^^^^^ + +error: negative impls are not allowed for marker traits + --> $DIR/negative-impl-marker-traits.rs:8:6 + | +LL | impl !Trait for Local {} + | ^ + | +note: marker trait + --> $DIR/negative-impl-marker-traits.rs:3:7 + | +LL | trait Trait {} + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/marker_trait_attr/forbidden-fruit.rs b/src/test/ui/marker_trait_attr/forbidden-fruit.rs new file mode 100644 index 0000000000000..2b3d90228fca0 --- /dev/null +++ b/src/test/ui/marker_trait_attr/forbidden-fruit.rs @@ -0,0 +1,20 @@ +#![feature(marker_trait_attr)] +#[marker] +pub trait Marker {} + +pub struct B; + +trait NotMarker { + type Assoc; +} + +impl NotMarker for B { + type Assoc = usize; +} + +impl NotMarker for T { + //~^ ERROR conflicting implementations of trait `NotMarker` for type `B` + type Assoc = Box; +} + +fn main() {} diff --git a/src/test/ui/marker_trait_attr/forbidden-fruit.stderr b/src/test/ui/marker_trait_attr/forbidden-fruit.stderr new file mode 100644 index 0000000000000..8a43bc63091e6 --- /dev/null +++ b/src/test/ui/marker_trait_attr/forbidden-fruit.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `NotMarker` for type `B` + --> $DIR/forbidden-fruit.rs:15:1 + | +LL | impl NotMarker for B { + | -------------------- first implementation here +... +LL | impl NotMarker for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `B` + | + = note: downstream crates may implement trait `Marker` for type `B` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr index 1f34105979441..a79e031199809 100644 --- a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr +++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied - --> $DIR/overlap-marker-trait.rs:27:17 +error[E0283]: type annotations needed + --> $DIR/overlap-marker-trait.rs:27:5 | LL | is_marker::(); - | ^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for struct `NotDebugOrDisplay` | + = note: cannot satisfy `NotDebugOrDisplay: Marker` note: required by a bound in `is_marker` --> $DIR/overlap-marker-trait.rs:15:17 | @@ -12,4 +13,4 @@ LL | fn is_marker() { } error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0283`.