1
Fork 0

Rollup merge of #134573 - lukas-code:unimpl-dyn-pointerlike, r=compiler-errors

unimplement `PointerLike` for trait objects

Values of type `dyn* PointerLike` or `dyn PointerLike` are not pointer-like so these types should not implement `PointerLike`.

After https://github.com/rust-lang/rust/pull/133226, `PointerLike` allows user implementations, so we can't just mark it with `#[rustc_deny_explicit_impl(implement_via_object = false)]`. Instead, this PR splits the `#[rustc_deny_explicit_impl(implement_via_object = ...)]` attribute into two separate attributes `#[rustc_deny_explicit_impl]` and `#[rustc_do_not_implement_via_object]` so that we opt out of the automatic `impl PointerLike for dyn PointerLike` and still allow user implementations.

For traits that are marked with `#[do_not_implement_via_object]` but not `#[rustc_deny_explicit_impl]` I've also made it possible to add a manual `impl Trait for dyn Trait`. There is no immediate need for this, but it was one line to implement and seems nice to have.

fixes https://github.com/rust-lang/rust/issues/134545
fixes https://github.com/rust-lang/rust/issues/134543

r? `@compiler-errors`
This commit is contained in:
Matthias Krüger 2024-12-20 21:32:33 +01:00 committed by GitHub
commit 0b1834d66b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 217 additions and 93 deletions

View file

@ -912,11 +912,20 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!( rustc_attr!(
rustc_deny_explicit_impl, rustc_deny_explicit_impl,
AttributeType::Normal, AttributeType::Normal,
template!(List: "implement_via_object = (true|false)"), template!(Word),
ErrorFollowing, ErrorFollowing,
EncodeCrossCrate::No, EncodeCrossCrate::No,
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
), ),
rustc_attr!(
rustc_do_not_implement_via_object,
AttributeType::Normal,
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
(`impl Trait for dyn Trait`)"
),
rustc_attr!( rustc_attr!(
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes, ErrorFollowing, EncodeCrossCrate::Yes,

View file

@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>(
// so this is valid. // so this is valid.
} else { } else {
let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id); let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
if supertrait_def_ids.any(|d| d == trait_def_id) { if supertrait_def_ids
.any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
{
let span = tcx.def_span(impl_def_id); let span = tcx.def_span(impl_def_id);
return Err(struct_span_code_err!( return Err(struct_span_code_err!(
tcx.dcx(), tcx.dcx(),

View file

@ -1261,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
no_dups.then_some(list) no_dups.then_some(list)
}); });
let mut deny_explicit_impl = false; let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
let mut implement_via_object = true; let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
deny_explicit_impl = true;
let mut seen_attr = false;
for meta in attr.meta_item_list().iter().flatten() {
if let Some(meta) = meta.meta_item()
&& meta.name_or_empty() == sym::implement_via_object
&& let Some(lit) = meta.name_value_literal()
{
if seen_attr {
tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item");
}
seen_attr = true;
match lit.symbol {
kw::True => {
implement_via_object = true;
}
kw::False => {
implement_via_object = false;
}
_ => {
tcx.dcx().span_err(
meta.span,
format!(
"unknown literal passed to `implement_via_object` attribute: {}",
lit.symbol
),
);
}
}
} else {
tcx.dcx().span_err(
meta.span(),
format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"),
);
}
}
if !seen_attr {
tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item");
}
}
ty::TraitDef { ty::TraitDef {
def_id: def_id.to_def_id(), def_id: def_id.to_def_id(),

View file

@ -70,12 +70,12 @@ pub struct TraitDef {
/// Whether to add a builtin `dyn Trait: Trait` implementation. /// Whether to add a builtin `dyn Trait: Trait` implementation.
/// This is enabled for all traits except ones marked with /// This is enabled for all traits except ones marked with
/// `#[rustc_deny_explicit_impl(implement_via_object = false)]`. /// `#[rustc_do_not_implement_via_object]`.
pub implement_via_object: bool, pub implement_via_object: bool,
/// Whether a trait is fully built-in, and any implementation is disallowed. /// Whether a trait is fully built-in, and any implementation is disallowed.
/// This only applies to built-in traits, and is marked via /// This only applies to built-in traits, and is marked via
/// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`. /// `#[rustc_deny_explicit_impl]`.
pub deny_explicit_impl: bool, pub deny_explicit_impl: bool,
} }

View file

@ -186,6 +186,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::rustc_coinductive, ..] [sym::rustc_coinductive, ..]
| [sym::rustc_must_implement_one_of, ..] | [sym::rustc_must_implement_one_of, ..]
| [sym::rustc_deny_explicit_impl, ..] | [sym::rustc_deny_explicit_impl, ..]
| [sym::rustc_do_not_implement_via_object, ..]
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),

View file

@ -1717,6 +1717,7 @@ symbols! {
rustc_diagnostic_macros, rustc_diagnostic_macros,
rustc_dirty, rustc_dirty,
rustc_do_not_const_check, rustc_do_not_const_check,
rustc_do_not_implement_via_object,
rustc_doc_primitive, rustc_doc_primitive,
rustc_driver, rustc_driver,
rustc_dummy, rustc_dummy,

View file

@ -133,7 +133,9 @@ pub trait AsyncDrop {
} }
#[lang = "async_destruct"] #[lang = "async_destruct"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
trait AsyncDestruct { trait AsyncDestruct {
type AsyncDestructor: Future<Output = ()>; type AsyncDestructor: Future<Output = ()>;
} }

View file

@ -141,7 +141,9 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
)] )]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait] #[rustc_specialization_trait]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[rustc_coinductive] #[rustc_coinductive]
pub trait Sized { pub trait Sized {
// Empty. // Empty.
@ -181,7 +183,9 @@ pub trait Sized {
/// [^1]: Formerly known as *object safe*. /// [^1]: Formerly known as *object safe*.
#[unstable(feature = "unsize", issue = "18598")] #[unstable(feature = "unsize", issue = "18598")]
#[lang = "unsize"] #[lang = "unsize"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Unsize<T: ?Sized> { pub trait Unsize<T: ?Sized> {
// Empty. // Empty.
} }
@ -815,7 +819,9 @@ impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
)] )]
#[lang = "discriminant_kind"] #[lang = "discriminant_kind"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait DiscriminantKind { pub trait DiscriminantKind {
/// The type of the discriminant, which must satisfy the trait /// The type of the discriminant, which must satisfy the trait
/// bounds required by `mem::Discriminant`. /// bounds required by `mem::Discriminant`.
@ -956,7 +962,9 @@ marker_impls! {
#[unstable(feature = "const_destruct", issue = "133214")] #[unstable(feature = "const_destruct", issue = "133214")]
#[lang = "destruct"] #[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[cfg_attr(not(bootstrap), const_trait)] #[cfg_attr(not(bootstrap), const_trait)]
pub trait Destruct {} pub trait Destruct {}
@ -967,19 +975,22 @@ pub trait Destruct {}
#[unstable(feature = "tuple_trait", issue = "none")] #[unstable(feature = "tuple_trait", issue = "none")]
#[lang = "tuple_trait"] #[lang = "tuple_trait"]
#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] #[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Tuple {} pub trait Tuple {}
/// A marker for pointer-like types. /// A marker for pointer-like types.
/// ///
/// All types that have the same size and alignment as a `usize` or /// This trait can only be implemented for types that have the same size and alignment
/// `*const ()` automatically implement this trait. /// as a `usize` or `*const ()`.
#[unstable(feature = "pointer_like_trait", issue = "none")] #[unstable(feature = "pointer_like_trait", issue = "none")]
#[lang = "pointer_like"] #[lang = "pointer_like"]
#[diagnostic::on_unimplemented( #[diagnostic::on_unimplemented(
message = "`{Self}` needs to have the same ABI as a pointer", message = "`{Self}` needs to have the same ABI as a pointer",
label = "`{Self}` needs to be a pointer-like type" label = "`{Self}` needs to be a pointer-like type"
)] )]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait PointerLike {} pub trait PointerLike {}
#[cfg(not(bootstrap))] #[cfg(not(bootstrap))]
@ -1068,7 +1079,9 @@ marker_impls! {
reason = "internal trait for implementing various traits for all function pointers" reason = "internal trait for implementing various traits for all function pointers"
)] )]
#[lang = "fn_ptr_trait"] #[lang = "fn_ptr_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait FnPtr: Copy + Clone { pub trait FnPtr: Copy + Clone {
/// Returns the address of the function pointer. /// Returns the address of the function pointer.
#[lang = "fn_ptr_addr"] #[lang = "fn_ptr_addr"]

View file

@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
/// `usize` is stable, but not portable. /// `usize` is stable, but not portable.
#[unstable(feature = "transmutability", issue = "99571")] #[unstable(feature = "transmutability", issue = "99571")]
#[lang = "transmute_trait"] #[lang = "transmute_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
#[rustc_coinductive] #[rustc_coinductive]
pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }> pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
where where

View file

@ -53,7 +53,9 @@ use crate::ptr::NonNull;
/// ///
/// [`to_raw_parts`]: *const::to_raw_parts /// [`to_raw_parts`]: *const::to_raw_parts
#[lang = "pointee_trait"] #[lang = "pointee_trait"]
#[rustc_deny_explicit_impl(implement_via_object = false)] #[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
pub trait Pointee { pub trait Pointee {
/// The type for metadata in pointers and references to `Self`. /// The type for metadata in pointers and references to `Self`.
#[lang = "metadata_type"] #[lang = "metadata_type"]

View file

@ -0,0 +1,23 @@
// Test that `dyn PointerLike` and `dyn* PointerLike` do not implement `PointerLike`.
// This used to ICE during codegen.
#![crate_type = "lib"]
#![feature(pointer_like_trait, dyn_star)]
#![feature(unsized_fn_params)]
#![expect(incomplete_features)]
#![expect(internal_features)]
use std::marker::PointerLike;
pub fn lol(x: dyn* PointerLike) {
foo(x); //~ ERROR `dyn* PointerLike` needs to have the same ABI as a pointer
}
pub fn uwu(x: dyn PointerLike) {
foo(x); //~ ERROR `dyn PointerLike` needs to have the same ABI as a pointer
}
fn foo<T: PointerLike + ?Sized>(x: T) {
let _: dyn* PointerLike = x;
}

View file

@ -0,0 +1,39 @@
error[E0277]: `dyn* PointerLike` needs to have the same ABI as a pointer
--> $DIR/dyn-pointer-like.rs:14:9
|
LL | foo(x);
| --- ^ the trait `PointerLike` is not implemented for `dyn* PointerLike`
| |
| required by a bound introduced by this call
|
= note: the trait bound `dyn* PointerLike: PointerLike` is not satisfied
note: required by a bound in `foo`
--> $DIR/dyn-pointer-like.rs:21:11
|
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
| ^^^^^^^^^^^ required by this bound in `foo`
help: consider borrowing here
|
LL | foo(&x);
| +
LL | foo(&mut x);
| ++++
error[E0277]: `dyn PointerLike` needs to have the same ABI as a pointer
--> $DIR/dyn-pointer-like.rs:18:9
|
LL | foo(x);
| --- ^ `dyn PointerLike` needs to be a pointer-like type
| |
| required by a bound introduced by this call
|
= help: the trait `PointerLike` is not implemented for `dyn PointerLike`
note: required by a bound in `foo`
--> $DIR/dyn-pointer-like.rs:21:11
|
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
| ^^^^^^^^^^^ required by this bound in `foo`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,20 +1,44 @@
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
--> $DIR/deny-builtin-object-impl.rs:19:23 --> $DIR/deny-builtin-object-impl.rs:20:1
| |
LL | test_not_object::<dyn NotObject>(); LL | impl NotImplYesObject for () {}
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:37:32
|
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
| |
help: this trait has no implementations, consider adding one help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:11:1 --> $DIR/deny-builtin-object-impl.rs:12:1
| |
LL | trait NotObject {} LL | trait NotImplNotObject {}
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_not_object` note: required by a bound in `test_not_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:15:23 --> $DIR/deny-builtin-object-impl.rs:28:32
| |
LL | fn test_not_object<T: NotObject + ?Sized>() {} LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
| ^^^^^^^^^ required by this bound in `test_not_object` | ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
error: aborting due to 1 previous error error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:40:32
|
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
|
help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:15:1
|
LL | trait YesImplNotObject {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_yes_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:30:32
|
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
For more information about this error, try `rustc --explain E0277`. error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0322.
For more information about an error, try `rustc --explain E0277`.

View file

@ -1,20 +1,44 @@
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
--> $DIR/deny-builtin-object-impl.rs:19:23 --> $DIR/deny-builtin-object-impl.rs:20:1
| |
LL | test_not_object::<dyn NotObject>(); LL | impl NotImplYesObject for () {}
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:37:32
|
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
| |
help: this trait has no implementations, consider adding one help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:11:1 --> $DIR/deny-builtin-object-impl.rs:12:1
| |
LL | trait NotObject {} LL | trait NotImplNotObject {}
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_not_object` note: required by a bound in `test_not_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:15:23 --> $DIR/deny-builtin-object-impl.rs:28:32
| |
LL | fn test_not_object<T: NotObject + ?Sized>() {} LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
| ^^^^^^^^^ required by this bound in `test_not_object` | ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
error: aborting due to 1 previous error error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
--> $DIR/deny-builtin-object-impl.rs:40:32
|
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
|
help: this trait has no implementations, consider adding one
--> $DIR/deny-builtin-object-impl.rs:15:1
|
LL | trait YesImplNotObject {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `test_yes_impl_not_object`
--> $DIR/deny-builtin-object-impl.rs:30:32
|
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
For more information about this error, try `rustc --explain E0277`. error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0322.
For more information about an error, try `rustc --explain E0277`.

View file

@ -4,18 +4,41 @@
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#[rustc_deny_explicit_impl(implement_via_object = true)] #[rustc_deny_explicit_impl]
trait YesObject {} trait NotImplYesObject {}
#[rustc_deny_explicit_impl(implement_via_object = false)] #[rustc_deny_explicit_impl]
trait NotObject {} #[rustc_do_not_implement_via_object]
trait NotImplNotObject {}
fn test_yes_object<T: YesObject + ?Sized>() {} #[rustc_do_not_implement_via_object]
trait YesImplNotObject {}
fn test_not_object<T: NotObject + ?Sized>() {} #[rustc_do_not_implement_via_object]
trait YesImplNotObject2 {}
impl NotImplYesObject for () {}
//~^ ERROR explicit impls for the `NotImplYesObject` trait are not permitted
// If there is no automatic impl then we can add a manual impl:
impl YesImplNotObject2 for dyn YesImplNotObject2 {}
fn test_not_impl_yes_object<T: NotImplYesObject + ?Sized>() {}
fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
fn test_yes_impl_not_object2<T: YesImplNotObject2 + ?Sized>() {}
fn main() { fn main() {
test_yes_object::<dyn YesObject>(); test_not_impl_yes_object::<dyn NotImplYesObject>();
test_not_object::<dyn NotObject>();
//~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied test_not_impl_not_object::<dyn NotImplNotObject>();
//~^ ERROR the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
test_yes_impl_not_object::<dyn YesImplNotObject>();
//~^ ERROR the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
test_yes_impl_not_object2::<dyn YesImplNotObject2>();
} }