From 9e1c600f74f966ec583f0ac39d0c2a103a2560a7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 18 Jan 2023 22:43:05 -0800 Subject: [PATCH 1/2] Disallow impl autotrait for trait object --- compiler/rustc_data_structures/src/sync.rs | 4 +- .../src/coherence/orphan.rs | 201 ++++++++++++++---- ...ce-impl-trait-for-marker-trait-negative.rs | 23 +- ...mpl-trait-for-marker-trait-negative.stderr | 42 +++- ...ce-impl-trait-for-marker-trait-positive.rs | 23 +- ...mpl-trait-for-marker-trait-positive.stderr | 42 +++- 6 files changed, 267 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index ed5341c40ef08..ad71dcdf9d953 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -31,8 +31,8 @@ cfg_if! { pub auto trait Send {} pub auto trait Sync {} - impl Send for T {} - impl Sync for T {} + impl Send for T {} + impl Sync for T {} #[macro_export] macro_rules! rustc_erase_owner { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 95b03eb8263fd..5c478b96fe6bb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IgnoreRegions; use rustc_middle::ty::{ - self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::lint; use rustc_span::def_id::{DefId, LocalDefId}; @@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>( // struct B { } // impl Foo for A { } // impl Foo for B { } - // impl !Send for (A, B) { } + // impl !Foo for (A, B) { } // ``` // // This final impl is legal according to the orphan @@ -99,50 +99,171 @@ fn do_orphan_check_impl<'tcx>( tcx.trait_is_auto(trait_def_id) ); - if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { + if tcx.trait_is_auto(trait_def_id) { let self_ty = trait_ref.self_ty(); - let opt_self_def_id = match *self_ty.kind() { - ty::Adt(self_def, _) => Some(self_def.did()), - ty::Foreign(did) => Some(did), - _ => None, - }; - let msg = match opt_self_def_id { - // We only want to permit nominal types, but not *all* nominal types. - // They must be local to the current crate, so that people - // can't do `unsafe impl Send for Rc` or - // `impl !Send for Box`. - Some(self_def_id) => { - if self_def_id.is_local() { - None + // If the impl is in the same crate as the auto-trait, almost anything + // goes. + // + // impl MyAuto for Rc {} // okay + // impl !MyAuto for *const T {} // okay + // impl MyAuto for T {} // okay + // + // But there is one important exception: implementing for a trait object + // is not allowed. + // + // impl MyAuto for dyn Trait {} // NOT OKAY + // impl MyAuto for T {} // NOT OKAY + // + enum LocalImpl { + Allow, + Disallow { problematic_kind: &'static str }, + } + + // If the auto-trait is from a dependency, it must only be getting + // implemented for a nominal type, and specifically one local to the + // current crate. + // + // impl Sync for MyStruct {} // okay + // + // impl Sync for Rc {} // NOT OKAY + enum NonlocalImpl { + Allow, + DisallowBecauseNonlocal, + DisallowOther, + } + + // Exhaustive match considering that this logic is essential for + // soundness. + let (local_impl, nonlocal_impl) = match self_ty.kind() { + // struct Struct; + // impl AutoTrait for Struct {} + ty::Adt(self_def, _) => ( + LocalImpl::Allow, + if self_def.did().is_local() { + NonlocalImpl::Allow + } else { + NonlocalImpl::DisallowBecauseNonlocal + }, + ), + + // extern { type OpaqueType; } + // impl AutoTrait for OpaqueType {} + ty::Foreign(did) => ( + LocalImpl::Allow, + if did.is_local() { + NonlocalImpl::Allow } else { - Some(( - format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - tcx.def_path_str(trait_def_id) - ), - "can't implement cross-crate trait for type in another crate", - )) + NonlocalImpl::DisallowBecauseNonlocal + }, + ), + + // impl AutoTrait for dyn Trait {} + ty::Dynamic(..) => ( + LocalImpl::Disallow { problematic_kind: "trait object" }, + NonlocalImpl::DisallowOther, + ), + + // impl AutoTrait for T {} + // impl AutoTrait for T {} + ty::Param(..) => ( + if self_ty.is_sized(tcx, tcx.param_env(def_id)) { + LocalImpl::Allow + } else { + LocalImpl::Disallow { problematic_kind: "generic type" } + }, + NonlocalImpl::DisallowOther, + ), + + // trait Id { type This: ?Sized; } + // impl Id for T { + // type This = T; + // } + // impl AutoTrait for ::This {} + ty::Alias(AliasKind::Projection, _) => ( + LocalImpl::Disallow { problematic_kind: "associated type" }, + NonlocalImpl::DisallowOther, + ), + + // type Opaque = impl Trait; + // impl AutoTrait for Opaque {} + ty::Alias(AliasKind::Opaque, _) => ( + LocalImpl::Disallow { problematic_kind: "opaque type" }, + NonlocalImpl::DisallowOther, + ), + + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Never + | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther), + + ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) => span_bug!(sp, "weird self type for autotrait impl"), + + ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow), + }; + + if trait_def_id.is_local() { + match local_impl { + LocalImpl::Allow => {} + LocalImpl::Disallow { problematic_kind } => { + let msg = format!( + "traits with a default impl, like `{trait}`, \ + cannot be implemented for {problematic_kind} `{self_ty}`", + trait = tcx.def_path_str(trait_def_id), + ); + let label = format!( + "a trait object implements `{trait}` if and only if `{trait}` \ + is one of the trait object's trait bounds", + trait = tcx.def_path_str(trait_def_id), + ); + let reported = + struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit(); + return Err(reported); } } - _ => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, can \ + } else { + if let Some((msg, label)) = match nonlocal_impl { + NonlocalImpl::Allow => None, + NonlocalImpl::DisallowBecauseNonlocal => Some(( + format!( + "cross-crate traits with a default impl, like `{}`, \ + can only be implemented for a struct/enum type \ + defined in the current crate", + tcx.def_path_str(trait_def_id) + ), + "can't implement cross-crate trait for type in another crate", + )), + NonlocalImpl::DisallowOther => Some(( + format!( + "cross-crate traits with a default impl, like `{}`, can \ only be implemented for a struct/enum type, not `{}`", - tcx.def_path_str(trait_def_id), - self_ty - ), - "can't implement cross-crate trait with a default impl for \ - non-struct/enum type", - )), - }; - - if let Some((msg, label)) = msg { - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); - return Err(reported); + tcx.def_path_str(trait_def_id), + self_ty + ), + "can't implement cross-crate trait with a default impl for \ + non-struct/enum type", + )), + } { + let reported = + struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); + return Err(reported); + } } } diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs index 50d9a480ad1e5..98f1558b7ffe1 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs @@ -12,19 +12,26 @@ auto trait Marker2 {} trait Object: Marker1 {} // A supertrait marker is illegal... -impl !Marker1 for dyn Object + Marker2 { } //~ ERROR E0371 +impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371 + //~^ ERROR 0321 // ...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 +impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371 + //~^ ERROR 0321 // 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. +// Implementing a marker for a local trait object is forbidden by a special +// orphan-like rule. +impl !Marker2 for dyn Object {} //~ ERROR E0321 impl !Send for dyn Object {} //~ ERROR E0321 impl !Send for dyn Object + Marker2 {} //~ ERROR E0321 -fn main() { } +// Blanket impl that applies to dyn Object is equally problematic. +auto trait Marker3 {} +impl !Marker3 for T {} //~ ERROR E0321 + +auto trait Marker4 {} +impl !Marker4 for T {} // okay + +fn main() {} diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index c364c707ff9ea..ea38afc40ce80 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -1,17 +1,41 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 | -LL | impl !Marker1 for dyn Object + Marker2 { } +LL | impl !Marker1 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` +error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 + | +LL | impl !Marker1 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds + error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 | -LL | impl !Marker2 for dyn Object + Marker2 { } +LL | impl !Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` +error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 + | +LL | impl !Marker2 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds + +error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1 + | +LL | impl !Marker2 for dyn Object {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1 | LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^----------- @@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i LL | impl !Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error: aborting due to 5 previous errors +error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1 + | +LL | impl !Marker3 for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs index faac6d983f31e..db2e2b4509a2a 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs @@ -12,19 +12,26 @@ auto trait Marker2 {} trait Object: Marker1 {} // A supertrait marker is illegal... -impl Marker1 for dyn Object + Marker2 { } //~ ERROR E0371 +impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371 + //~^ ERROR E0321 // ...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 +impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371 + //~^ ERROR E0321 // 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. +// Implementing a marker for a local trait object is forbidden by a special +// orphan-like rule. +impl Marker2 for dyn Object {} //~ ERROR E0321 unsafe impl Send for dyn Object {} //~ ERROR E0321 unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321 -fn main() { } +// Blanket impl that applies to dyn Object is equally problematic. +auto trait Marker3 {} +impl Marker3 for T {} //~ ERROR E0321 + +auto trait Marker4 {} +impl Marker4 for T {} // okay + +fn main() {} diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index b80429794f92c..2a8713bc32794 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -1,17 +1,41 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 | -LL | impl Marker1 for dyn Object + Marker2 { } +LL | impl Marker1 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` +error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 + | +LL | impl Marker1 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds + error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1 | -LL | impl Marker2 for dyn Object + Marker2 { } +LL | impl Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` +error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1 + | +LL | impl Marker2 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds + +error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1 + | +LL | impl Marker2 for dyn Object {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1 | LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^----------- @@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i LL | unsafe impl Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error: aborting due to 5 previous errors +error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1 + | +LL | impl Marker3 for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. From 4501d3abe17a3dc10f0dffcb38be04b58a33bafb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Jan 2023 01:24:45 -0800 Subject: [PATCH 2/2] Autotrait bounds on dyn-safe trait methods --- .../src/coherence/orphan.rs | 22 +++++++ .../src/traits/object_safety.rs | 60 +++++++++++++++---- .../self-in-where-clause-allowed.rs | 23 +++++++ .../self-in-where-clause-allowed.stderr | 15 +++++ 4 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 tests/ui/where-clauses/self-in-where-clause-allowed.rs create mode 100644 tests/ui/where-clauses/self-in-where-clause-allowed.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 5c478b96fe6bb..7d381d8902ac2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -115,6 +115,28 @@ fn do_orphan_check_impl<'tcx>( // impl MyAuto for dyn Trait {} // NOT OKAY // impl MyAuto for T {} // NOT OKAY // + // With this restriction, it's guaranteed that an auto-trait is + // implemented for a trait object if and only if the auto-trait is one + // of the trait object's trait bounds (or a supertrait of a bound). In + // other words `dyn Trait + AutoTrait` always implements AutoTrait, + // while `dyn Trait` never implements AutoTrait. + // + // This is necessary in order for autotrait bounds on methods of trait + // objects to be sound. + // + // auto trait AutoTrait {} + // + // trait ObjectSafeTrait { + // fn f(&self) where Self: AutoTrait; + // } + // + // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`. + // + // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound + // for the ObjectSafeTrait shown above to be object safe because someone + // could take some type implementing ObjectSafeTrait but not AutoTrait, + // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no + // concrete implementation (issue #50781). enum LocalImpl { Allow, Disallow { problematic_kind: &'static str }, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 565cfca9090e1..8f548acfd2eac 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -547,16 +547,56 @@ fn virtual_call_violation_for_method<'tcx>( // NOTE: This check happens last, because it results in a lint, and not a // hard error. - if tcx - .predicates_of(method.def_id) - .predicates - .iter() - // A trait object can't claim to live more than the concrete type, - // so outlives predicates will always hold. - .cloned() - .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred)) - { + if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| { + // dyn Trait is okay: + // + // trait Trait { + // fn f(&self) where Self: 'static; + // } + // + // because a trait object can't claim to live longer than the concrete + // type. If the lifetime bound holds on dyn Trait then it's guaranteed + // to hold as well on the concrete type. + if pred.to_opt_type_outlives().is_some() { + return false; + } + + // dyn Trait is okay: + // + // auto trait AutoTrait {} + // + // trait Trait { + // fn f(&self) where Self: AutoTrait; + // } + // + // because `impl AutoTrait for dyn Trait` is disallowed by coherence. + // Traits with a default impl are implemented for a trait object if and + // only if the autotrait is one of the trait object's trait bounds, like + // in `dyn Trait + AutoTrait`. This guarantees that trait objects only + // implement auto traits if the underlying type does as well. + if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + trait_ref: pred_trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + })) = pred.kind().skip_binder() + && pred_trait_ref.self_ty() == tcx.types.self_param + && tcx.trait_is_auto(pred_trait_ref.def_id) + { + // Consider bounds like `Self: Bound`. Auto traits are not + // allowed to have generic parameters so `auto trait Bound {}` + // would already have reported an error at the definition of the + // auto trait. + if pred_trait_ref.substs.len() != 1 { + tcx.sess.diagnostic().delay_span_bug( + span, + "auto traits cannot have generic parameters", + ); + } + return false; + } + + contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone()) + }) { return Some(MethodViolationCode::WhereClauseReferencesSelf); } diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.rs b/tests/ui/where-clauses/self-in-where-clause-allowed.rs new file mode 100644 index 0000000000000..6cf5ed2e46aec --- /dev/null +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.rs @@ -0,0 +1,23 @@ +// check-fail + +#![feature(auto_traits)] +#![deny(where_clauses_object_safety)] + +auto trait AutoTrait {} + +trait Trait { + fn static_lifetime_bound(&self) where Self: 'static {} + + fn arg_lifetime_bound<'a>(&self, _arg: &'a ()) where Self: 'a {} + + fn autotrait_bound(&self) where Self: AutoTrait {} +} + +impl Trait for () {} + +fn main() { + let trait_object = &() as &dyn Trait; + trait_object.static_lifetime_bound(); + trait_object.arg_lifetime_bound(&()); + trait_object.autotrait_bound(); //~ ERROR: the trait bound `dyn Trait: AutoTrait` is not satisfied +} diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr new file mode 100644 index 0000000000000..ea51f5084f875 --- /dev/null +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied + --> $DIR/self-in-where-clause-allowed.rs:22:18 + | +LL | trait_object.autotrait_bound(); + | ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait` + | +note: required by a bound in `Trait::autotrait_bound` + --> $DIR/self-in-where-clause-allowed.rs:13:43 + | +LL | fn autotrait_bound(&self) where Self: AutoTrait {} + | ^^^^^^^^^ required by this bound in `Trait::autotrait_bound` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.