about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2024-12-20 16:57:14 +0100
committerLukas Markeffsky <@>2024-12-20 16:57:14 +0100
commit42c00cb6479d6e03742968e06c6d280a272acd53 (patch)
treec31e60187c98f3a54e3ad4dec73e7b258241c37e
parent8a1f8039a7ded79d3d4fe97b110016d89f2b11e2 (diff)
downloadrust-42c00cb6479d6e03742968e06c6d280a272acd53.tar.gz
rust-42c00cb6479d6e03742968e06c6d280a272acd53.zip
split up `#[rustc_deny_explicit_impl]` attribute
This commit splits the `#[rustc_deny_explicit_impl(implement_via_object = ...)]` attribute
into two attributes `#[rustc_deny_explicit_impl]` and `#[rustc_do_not_implement_via_object]`.

This allows us to have special traits that can have user-defined impls but do not have the
automatic trait impl for trait objects (`impl Trait for dyn Trait`).
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs45
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/future/async_drop.rs4
-rw-r--r--library/core/src/marker.rs24
-rw-r--r--library/core/src/mem/transmutability.rs4
-rw-r--r--library/core/src/ptr/metadata.rs4
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.current.stderr50
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.next.stderr50
-rw-r--r--tests/ui/traits/deny-builtin-object-impl.rs41
13 files changed, 152 insertions, 91 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4b9f62fa764..63e5ebb8688 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -912,12 +912,21 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_deny_explicit_impl,
         AttributeType::Normal,
-        template!(List: "implement_via_object = (true|false)"),
+        template!(Word),
         ErrorFollowing,
         EncodeCrossCrate::No,
         "#[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_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
         ErrorFollowing, EncodeCrossCrate::Yes,
         "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 3aad4bafeb5..1be4aa2f63a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>(
                 // so this is valid.
             } else {
                 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);
                     return Err(struct_span_code_err!(
                         tcx.dcx(),
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5e662bb96bc..ada70117b62 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1261,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
             no_dups.then_some(list)
         });
 
-    let mut deny_explicit_impl = false;
-    let mut implement_via_object = true;
-    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");
-        }
-    }
+    let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
+    let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
 
     ty::TraitDef {
         def_id: def_id.to_def_id(),
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 188107e5d54..743ea33b20a 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -70,12 +70,12 @@ pub struct TraitDef {
 
     /// Whether to add a builtin `dyn Trait: Trait` implementation.
     /// 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,
 
     /// Whether a trait is fully built-in, and any implementation is disallowed.
     /// 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,
 }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2310dd9dc72..1f2d5671f7a 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -186,6 +186,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 [sym::rustc_coinductive, ..]
                 | [sym::rustc_must_implement_one_of, ..]
                 | [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::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
                 [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a7ff0576f92..123e4b1f01f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1717,6 +1717,7 @@ symbols! {
         rustc_diagnostic_macros,
         rustc_dirty,
         rustc_do_not_const_check,
+        rustc_do_not_implement_via_object,
         rustc_doc_primitive,
         rustc_driver,
         rustc_dummy,
diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs
index 7de5fe67cd0..ea6d3b800e6 100644
--- a/library/core/src/future/async_drop.rs
+++ b/library/core/src/future/async_drop.rs
@@ -133,7 +133,9 @@ pub trait AsyncDrop {
 }
 
 #[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 {
     type AsyncDestructor: Future<Output = ()>;
 }
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1620b949590..31b27b7ef26 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -141,7 +141,9 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
 )]
 #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
 #[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]
 pub trait Sized {
     // Empty.
@@ -181,7 +183,9 @@ pub trait Sized {
 /// [^1]: Formerly known as *object safe*.
 #[unstable(feature = "unsize", issue = "18598")]
 #[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> {
     // 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"
 )]
 #[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 {
     /// The type of the discriminant, which must satisfy the trait
     /// bounds required by `mem::Discriminant`.
@@ -956,7 +962,9 @@ marker_impls! {
 #[unstable(feature = "const_destruct", issue = "133214")]
 #[lang = "destruct"]
 #[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)]
 pub trait Destruct {}
 
@@ -967,7 +975,9 @@ pub trait Destruct {}
 #[unstable(feature = "tuple_trait", issue = "none")]
 #[lang = "tuple_trait"]
 #[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 {}
 
 /// A marker for pointer-like types.
@@ -1068,7 +1078,9 @@ marker_impls! {
     reason = "internal trait for implementing various traits for all function pointers"
 )]
 #[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 {
     /// Returns the address of the function pointer.
     #[lang = "fn_ptr_addr"]
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index 7fa3c334391..9cf587650d9 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
 /// `usize` is stable, but not portable.
 #[unstable(feature = "transmutability", issue = "99571")]
 #[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]
 pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
 where
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index ae9810e558a..b1d5e1fa3a0 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -53,7 +53,9 @@ use crate::ptr::NonNull;
 ///
 /// [`to_raw_parts`]: *const::to_raw_parts
 #[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 {
     /// The type for metadata in pointers and references to `Self`.
     #[lang = "metadata_type"]
diff --git a/tests/ui/traits/deny-builtin-object-impl.current.stderr b/tests/ui/traits/deny-builtin-object-impl.current.stderr
index 8423a2519b2..d6f4762d099 100644
--- a/tests/ui/traits/deny-builtin-object-impl.current.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.current.stderr
@@ -1,20 +1,44 @@
-error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
-  --> $DIR/deny-builtin-object-impl.rs:19:23
+error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
+  --> $DIR/deny-builtin-object-impl.rs:20:1
    |
-LL |     test_not_object::<dyn NotObject>();
-   |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
+LL | impl NotImplYesObject for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
+  --> $DIR/deny-builtin-object-impl.rs:12:1
+   |
+LL | trait NotImplNotObject {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `test_not_impl_not_object`
+  --> $DIR/deny-builtin-object-impl.rs:28:32
+   |
+LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
+   |                                ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
+
+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:11:1
+  --> $DIR/deny-builtin-object-impl.rs:15:1
    |
-LL | trait NotObject {}
-   | ^^^^^^^^^^^^^^^
-note: required by a bound in `test_not_object`
-  --> $DIR/deny-builtin-object-impl.rs:15:23
+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_not_object<T: NotObject + ?Sized>() {}
-   |                       ^^^^^^^^^ required by this bound in `test_not_object`
+LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
+   |                                ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0322.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/deny-builtin-object-impl.next.stderr b/tests/ui/traits/deny-builtin-object-impl.next.stderr
index 8423a2519b2..d6f4762d099 100644
--- a/tests/ui/traits/deny-builtin-object-impl.next.stderr
+++ b/tests/ui/traits/deny-builtin-object-impl.next.stderr
@@ -1,20 +1,44 @@
-error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
-  --> $DIR/deny-builtin-object-impl.rs:19:23
+error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
+  --> $DIR/deny-builtin-object-impl.rs:20:1
    |
-LL |     test_not_object::<dyn NotObject>();
-   |                       ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
+LL | impl NotImplYesObject for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
+  --> $DIR/deny-builtin-object-impl.rs:12:1
+   |
+LL | trait NotImplNotObject {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `test_not_impl_not_object`
+  --> $DIR/deny-builtin-object-impl.rs:28:32
+   |
+LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
+   |                                ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
+
+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:11:1
+  --> $DIR/deny-builtin-object-impl.rs:15:1
    |
-LL | trait NotObject {}
-   | ^^^^^^^^^^^^^^^
-note: required by a bound in `test_not_object`
-  --> $DIR/deny-builtin-object-impl.rs:15:23
+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_not_object<T: NotObject + ?Sized>() {}
-   |                       ^^^^^^^^^ required by this bound in `test_not_object`
+LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
+   |                                ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0322.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/deny-builtin-object-impl.rs b/tests/ui/traits/deny-builtin-object-impl.rs
index c16dcca8fbc..9d02ab7bd46 100644
--- a/tests/ui/traits/deny-builtin-object-impl.rs
+++ b/tests/ui/traits/deny-builtin-object-impl.rs
@@ -4,18 +4,41 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_deny_explicit_impl(implement_via_object = true)]
-trait YesObject {}
+#[rustc_deny_explicit_impl]
+trait NotImplYesObject {}
 
-#[rustc_deny_explicit_impl(implement_via_object = false)]
-trait NotObject {}
+#[rustc_deny_explicit_impl]
+#[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() {
-    test_yes_object::<dyn YesObject>();
-    test_not_object::<dyn NotObject>();
-    //~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied
+    test_not_impl_yes_object::<dyn NotImplYesObject>();
+
+    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>();
 }