Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EXPERIMENT] disable orphan check for marker traits #96766

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {:?}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 28 additions & 1 deletion compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and nega

unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations

impl !Send for TestType<i32> {}
impl !Send for TestType<i32> {} //~ ERROR found both positive and negative implementation

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@ LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
LL | unsafe impl<T: 'static> Send for TestType<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<i32>`:
--> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1
|
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
| ------------------------------------------------------ positive implementation here
...
LL | impl !Send for TestType<i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.
10 changes: 10 additions & 0 deletions src/test/ui/coherence/negative-impl-marker-traits.rs
Original file line number Diff line number Diff line change
@@ -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() {}
26 changes: 26 additions & 0 deletions src/test/ui/coherence/negative-impl-marker-traits.stderr
Original file line number Diff line number Diff line change
@@ -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

20 changes: 20 additions & 0 deletions src/test/ui/marker_trait_attr/forbidden-fruit.rs
Original file line number Diff line number Diff line change
@@ -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<T: Marker> NotMarker for T {
//~^ ERROR conflicting implementations of trait `NotMarker` for type `B`
type Assoc = Box<String>;
}

fn main() {}
14 changes: 14 additions & 0 deletions src/test/ui/marker_trait_attr/forbidden-fruit.stderr
Original file line number Diff line number Diff line change
@@ -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<T: Marker> 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`.
9 changes: 5 additions & 4 deletions src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
Original file line number Diff line number Diff line change
@@ -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::<NotDebugOrDisplay>();
| ^^^^^^^^^^^^^^^^^ 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
|
Expand All @@ -12,4 +13,4 @@ LL | fn is_marker<T: 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`.