about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <github333195615777966@oli-obk.de>2025-01-14 11:02:29 +0000
committerOli Scherer <github333195615777966@oli-obk.de>2025-02-25 08:06:30 +0000
commitffc955bcfb79063b51947d4846591bf162e7ddfe (patch)
treee7c8f443e1ac7cd9f7238a11f47d71a591efdd44
parentf5729cfed3c45e061e8a443677fc1d5ef9277df7 (diff)
downloadrust-ffc955bcfb79063b51947d4846591bf162e7ddfe.tar.gz
rust-ffc955bcfb79063b51947d4846591bf162e7ddfe.zip
Don't require method impls for methods with `Self:Sized` bounds for impls for unsized types
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs41
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs4
-rw-r--r--tests/ui/did_you_mean/recursion_limit_deref.stderr6
-rw-r--r--tests/ui/invalid/issue-114435-layout-type-err.rs7
-rw-r--r--tests/ui/invalid/issue-114435-layout-type-err.stderr4
-rw-r--r--tests/ui/traits/solver-cycles/129541-recursive-struct.multiple.stderr6
-rw-r--r--tests/ui/traits/solver-cycles/129541-recursive-struct.rs2
-rw-r--r--tests/ui/traits/solver-cycles/129541-recursive-struct.unique.stderr6
-rw-r--r--tests/ui/traits/trivial_impl_sized.rs24
-rw-r--r--tests/ui/traits/trivial_impl_sized.stderr24
11 files changed, 106 insertions, 20 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6badd290917..3f75cce0092 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -605,6 +605,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
 hir_analysis_unused_generic_parameter_ty_alias_help =
     consider removing `{$param_name}` or referring to it in the body of the type alias
 
+hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type
+
 hir_analysis_value_of_associated_struct_already_specified =
     the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
     .label = re-bound here
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 09320b86878..f2331f3fd8e 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -992,6 +992,32 @@ fn check_impl_items_against_trait<'tcx>(
 
     let trait_def = tcx.trait_def(trait_ref.def_id);
 
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
+
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
+    let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
+    let param_env = tcx.param_env(impl_id);
+
+    let self_is_guaranteed_unsized = match tcx
+        .struct_tail_raw(
+            trait_ref.self_ty(),
+            |ty| {
+                ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
+                    Ty::new_error_with_message(
+                        tcx,
+                        tcx.def_span(impl_id),
+                        "struct tail should be computable",
+                    )
+                })
+            },
+            || (),
+        )
+        .kind()
+    {
+        ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
+        _ => false,
+    };
+
     for &impl_item in impl_item_refs {
         let ty_impl_item = tcx.associated_item(impl_item);
         let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
@@ -1021,6 +1047,15 @@ fn check_impl_items_against_trait<'tcx>(
             }
         }
 
+        if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
+            tcx.emit_node_span_lint(
+                rustc_lint_defs::builtin::DEAD_CODE,
+                tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
+                tcx.def_span(ty_impl_item.def_id),
+                errors::UselessImplItem,
+            )
+        }
+
         check_specialization_validity(
             tcx,
             trait_def,
@@ -1044,7 +1079,11 @@ fn check_impl_items_against_trait<'tcx>(
                 .as_ref()
                 .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
 
-            if !is_implemented && tcx.defaultness(impl_id).is_final() {
+            if !is_implemented
+                && tcx.defaultness(impl_id).is_final()
+                // unsized types don't need to implement methods that have `Self: Sized` bounds.
+                && !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
+            {
                 missing_items.push(tcx.associated_item(trait_item_id));
             }
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 99262f9871e..852533ff5c9 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -908,6 +908,10 @@ pub(crate) enum ImplNotMarkedDefault {
     },
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_analysis_useless_impl_item)]
+pub(crate) struct UselessImplItem;
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_missing_trait_item, code = E0046)]
 pub(crate) struct MissingTraitItem {
diff --git a/tests/ui/did_you_mean/recursion_limit_deref.stderr b/tests/ui/did_you_mean/recursion_limit_deref.stderr
index b0c493faf1e..23341ec6bdc 100644
--- a/tests/ui/did_you_mean/recursion_limit_deref.stderr
+++ b/tests/ui/did_you_mean/recursion_limit_deref.stderr
@@ -1,3 +1,7 @@
+error: reached the recursion limit finding the struct tail for `K`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
+
 error: reached the recursion limit finding the struct tail for `Bottom`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
@@ -21,7 +25,7 @@ LL |     let x: &Bottom = &t;
    = note: expected reference `&Bottom`
               found reference `&Top`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0055, E0308.
 For more information about an error, try `rustc --explain E0055`.
diff --git a/tests/ui/invalid/issue-114435-layout-type-err.rs b/tests/ui/invalid/issue-114435-layout-type-err.rs
index f68744a13c1..2a86839e416 100644
--- a/tests/ui/invalid/issue-114435-layout-type-err.rs
+++ b/tests/ui/invalid/issue-114435-layout-type-err.rs
@@ -1,6 +1,6 @@
-//@ build-fail
+//@ check-fail
 //@ compile-flags: --crate-type lib -Cdebuginfo=2
-//@ error-pattern: the type has an unknown layout
+//@ error-pattern: recursion limit
 
 #![recursion_limit = "10"]
 macro_rules! link {
@@ -28,7 +28,6 @@ impl Bottom {
     }
 }
 
-
 link!(A, B);
 link!(B, C);
 link!(C, D);
@@ -41,4 +40,4 @@ link!(I, J);
 link!(J, K);
 link!(K, Bottom);
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/invalid/issue-114435-layout-type-err.stderr b/tests/ui/invalid/issue-114435-layout-type-err.stderr
index a2db74ff8bd..2fddc62f004 100644
--- a/tests/ui/invalid/issue-114435-layout-type-err.stderr
+++ b/tests/ui/invalid/issue-114435-layout-type-err.stderr
@@ -2,7 +2,5 @@ error: reached the recursion limit finding the struct tail for `Bottom`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
 
-error: the type has an unknown layout
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.multiple.stderr b/tests/ui/traits/solver-cycles/129541-recursive-struct.multiple.stderr
new file mode 100644
index 00000000000..93b064cdce2
--- /dev/null
+++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.multiple.stderr
@@ -0,0 +1,6 @@
+error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
index 4fbcbefec91..729771e560e 100644
--- a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
+++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
@@ -1,7 +1,7 @@
 // Regression test for #129541
 
 //@ revisions: unique multiple
-//@ check-pass
+//@ error-pattern: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
 
 trait Bound {}
 trait Normalize {
diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.unique.stderr b/tests/ui/traits/solver-cycles/129541-recursive-struct.unique.stderr
new file mode 100644
index 00000000000..93b064cdce2
--- /dev/null
+++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.unique.stderr
@@ -0,0 +1,6 @@
+error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/trivial_impl_sized.rs b/tests/ui/traits/trivial_impl_sized.rs
index 501a3405090..59cc079c268 100644
--- a/tests/ui/traits/trivial_impl_sized.rs
+++ b/tests/ui/traits/trivial_impl_sized.rs
@@ -1,5 +1,5 @@
-//! This test checks that we currently need to implement
-//! members, even if their where bounds don't hold for the impl type.
+//! This test checks that we do not need to implement
+//! members, whose `where Self: Sized` bounds don't hold for the impl type.
 
 trait Foo {
     fn foo()
@@ -15,12 +15,28 @@ impl Foo for () {
 impl Foo for i32 {}
 //~^ ERROR: not all trait items implemented, missing: `foo`
 
-// Should be allowed
 impl Foo for dyn std::fmt::Debug {}
-//~^ ERROR: not all trait items implemented, missing: `foo`
 
+#[deny(dead_code)]
 impl Foo for dyn std::fmt::Display {
     fn foo() {}
+    //~^ ERROR this item cannot be used as its where bounds are not satisfied
+}
+
+struct Struct {
+    i: i32,
+    tail: [u8],
 }
 
+impl Foo for Struct {}
+
+// Ensure we only allow known-unsized types to be skipped
+trait Trait {
+    fn foo(self)
+    where
+        Self: Sized;
+}
+impl<T: ?Sized> Trait for T {}
+//~^ ERROR: not all trait items implemented, missing: `foo`
+
 fn main() {}
diff --git a/tests/ui/traits/trivial_impl_sized.stderr b/tests/ui/traits/trivial_impl_sized.stderr
index ebf6dfc9dd2..95cab337182 100644
--- a/tests/ui/traits/trivial_impl_sized.stderr
+++ b/tests/ui/traits/trivial_impl_sized.stderr
@@ -9,17 +9,29 @@ LL | |         Self: Sized;
 LL |   impl Foo for i32 {}
    |   ^^^^^^^^^^^^^^^^ missing `foo` in implementation
 
+error: this item cannot be used as its where bounds are not satisfied for the `Self` type
+  --> $DIR/trivial_impl_sized.rs:22:5
+   |
+LL |     fn foo() {}
+   |     ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/trivial_impl_sized.rs:20:8
+   |
+LL | #[deny(dead_code)]
+   |        ^^^^^^^^^
+
 error[E0046]: not all trait items implemented, missing: `foo`
-  --> $DIR/trivial_impl_sized.rs:19:1
+  --> $DIR/trivial_impl_sized.rs:39:1
    |
-LL | /     fn foo()
+LL | /     fn foo(self)
 LL | |     where
 LL | |         Self: Sized;
    | |____________________- `foo` from trait
-...
-LL |   impl Foo for dyn std::fmt::Debug {}
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+LL |   }
+LL |   impl<T: ?Sized> Trait for T {}
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0046`.