about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood2@arm.com>2025-01-16 14:27:49 +0000
committerDavid Wood <david.wood2@arm.com>2025-06-16 15:00:22 +0000
commit3b0e1c17d285f5e8f93c07b5fc8f9c6aa277c0dd (patch)
treee27b0db7c88b60332b6790cf4aaeadca99ab8911
parentd43da6f4de19ccfc6ac5a8e6b16ab8cf2893692a (diff)
downloadrust-3b0e1c17d285f5e8f93c07b5fc8f9c6aa277c0dd.tar.gz
rust-3b0e1c17d285f5e8f93c07b5fc8f9c6aa277c0dd.zip
trait_sel: `{Meta,Pointee}Sized` on `?Sized` types
Expand the automatic implementation of `MetaSized` and `PointeeSized` so
that it is also implemented on non-`Sized` types, just not `ty::Foreign`
(extern type).
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs5
-rw-r--r--compiler/rustc_middle/src/query/keys.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs21
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs35
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs55
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs20
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs20
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs41
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs20
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs82
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs8
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs22
-rw-r--r--tests/ui/attributes/dump-preds.stderr1
-rw-r--r--tests/ui/feature-gates/feature-gate-sized-hierarchy.rs3
-rw-r--r--tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr47
-rw-r--r--tests/ui/sized-hierarchy/impls.rs307
-rw-r--r--tests/ui/sized-hierarchy/impls.stderr380
22 files changed, 907 insertions, 220 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b8dc01cbc03..20d0e87b7a7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1258,6 +1258,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant
     debug!(?item.owner_id);
 
     let def_id = item.owner_id.def_id;
+    if tcx.is_lang_item(def_id.into(), LangItem::PointeeSized) {
+        // `PointeeSized` is removed during lowering.
+        return Ok(());
+    }
+
     let trait_def = tcx.trait_def(def_id);
     if trait_def.is_marker
         || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 9ed1f10455a..4d914c42cfc 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -328,6 +328,14 @@ impl Key for (DefId, SimplifiedType) {
     }
 }
 
+impl Key for (DefId, ty::SizedTraitKind) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 impl<'tcx> Key for GenericArgsRef<'tcx> {
     type Cache<V> = DefaultCache<Self, V>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 15e8c1ef3cc..e4fcd7e56f1 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -81,8 +81,8 @@ use crate::ty::layout::ValidityRequirement;
 use crate::ty::print::{PrintTraitRefExt, describe_as_module};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{
-    self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
-    TyCtxtFeed,
+    self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty,
+    TyCtxt, TyCtxtFeed,
 };
 use crate::{dep_graph, mir, thir};
 
@@ -854,9 +854,10 @@ rustc_queries! {
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
-
-    query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) }
+    query adt_sizedness_constraint(
+        key: (DefId, SizedTraitKind)
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        desc { |tcx| "computing the sizedness constraint for `{}`", tcx.def_path_str(key.0) }
     }
 
     query adt_dtorck_constraint(
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index d92b4f9c06b..6d5a3abf665 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -229,8 +229,12 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
         )
     }
 
-    fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        self.sized_constraint(tcx)
+    fn sizedness_constraint(
+        self,
+        tcx: TyCtxt<'tcx>,
+        sizedness: ty::SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        self.sizedness_constraint(tcx, sizedness)
     }
 
     fn is_fundamental(self) -> bool {
@@ -634,10 +638,15 @@ impl<'tcx> AdtDef<'tcx> {
         tcx.adt_async_destructor(self.did())
     }
 
-    /// Returns a type such that `Self: Sized` if and only if that type is `Sized`,
-    /// or `None` if the type is always sized.
-    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None }
+    /// If this ADT is a struct, returns a type such that `Self: {Meta,Pointee,}Sized` if and only
+    /// if that type is `{Meta,Pointee,}Sized`, or `None` if this ADT is always
+    /// `{Meta,Pointee,}Sized`.
+    pub fn sizedness_constraint(
+        self,
+        tcx: TyCtxt<'tcx>,
+        sizedness: ty::SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        if self.is_struct() { tcx.adt_sizedness_constraint((self.did(), sizedness)) } else { None }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 0402d098822..97408e31854 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -60,6 +60,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
 )]
 use rustc_type_ir::inherent;
 pub use rustc_type_ir::relate::VarianceDiagInfo;
+pub use rustc_type_ir::solve::SizedTraitKind;
 pub use rustc_type_ir::*;
 #[allow(hidden_glob_reexports, unused_imports)]
 use rustc_type_ir::{InferCtxtLike, Interner};
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index cbf545c01c5..2adda8263a1 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1816,7 +1816,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
 
             ty::Adt(def, args) => def
-                .sized_constraint(tcx)
+                .sizedness_constraint(tcx, ty::SizedTraitKind::Sized)
                 .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 434e2a818bd..a300558c0c9 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -8,6 +8,7 @@ use std::ops::ControlFlow;
 use derive_where::derive_where;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{
     self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _,
     TypeVisitor, TypingMode, Upcast as _, elaborate,
@@ -203,31 +204,15 @@ where
         goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution>;
 
-    /// A type is `Sized` if its tail component is `Sized`.
+    /// A type is `Sized` if its tail component is `Sized` and a type is `MetaSized` if its tail
+    /// component is `MetaSized`.
     ///
     /// These components are given by built-in rules from
-    /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
-    fn consider_builtin_sized_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
-
-    /// A type is `MetaSized` if its tail component is `MetaSized`.
-    ///
-    /// These components are given by built-in rules from
-    /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
-    fn consider_builtin_meta_sized_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
-
-    /// A type is `PointeeSized` if its tail component is `PointeeSized`.
-    ///
-    /// These components are given by built-in rules from
-    /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
-    fn consider_builtin_pointee_sized_candidate(
+    /// [`structural_traits::instantiate_constituent_tys_for_sizedness_trait`].
+    fn consider_builtin_sizedness_candidates(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution>;
 
     /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
@@ -484,12 +469,14 @@ where
             G::consider_trait_alias_candidate(self, goal)
         } else {
             match cx.as_lang_item(trait_def_id) {
-                Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal),
+                Some(TraitSolverLangItem::Sized) => {
+                    G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
+                }
                 Some(TraitSolverLangItem::MetaSized) => {
-                    G::consider_builtin_meta_sized_candidate(self, goal)
+                    G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
                 }
                 Some(TraitSolverLangItem::PointeeSized) => {
-                    G::consider_builtin_pointee_sized_candidate(self, goal)
+                    unreachable!("`PointeeSized` is removed during lowering");
                 }
                 Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
                     G::consider_builtin_copy_clone_candidate(self, goal)
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 4a2a7761f7f..f39d3226009 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -5,6 +5,7 @@ use derive_where::derive_where;
 use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::solve::inspect::ProbeKind;
 use rustc_type_ir::{
     self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
@@ -104,8 +105,9 @@ where
 }
 
 #[instrument(level = "trace", skip(ecx), ret)]
-pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<D, I>(
+pub(in crate::solve) fn instantiate_constituent_tys_for_sizedness_trait<D, I>(
     ecx: &EvalCtxt<'_, D>,
+    sizedness: SizedTraitKind,
     ty: I::Ty,
 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>
 where
@@ -113,8 +115,9 @@ where
     I: Interner,
 {
     match ty.kind() {
-        // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
-        // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
+        // impl {Meta,}Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char
+        // impl {Meta,}Sized for &mut? T, [T; N], dyn* Trait, !, Coroutine, CoroutineWitness
+        // impl {Meta,}Sized for Closure, CoroutineClosure
         ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Uint(_)
         | ty::Int(_)
@@ -135,13 +138,16 @@ where
         | ty::Dynamic(_, _, ty::DynStar)
         | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
 
-        ty::Str
-        | ty::Slice(_)
-        | ty::Dynamic(..)
-        | ty::Foreign(..)
-        | ty::Alias(..)
-        | ty::Param(_)
-        | ty::Placeholder(..) => Err(NoSolution),
+        // impl {Meta,}Sized for str, [T], dyn Trait
+        ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
+            SizedTraitKind::Sized => Err(NoSolution),
+            SizedTraitKind::MetaSized => Ok(ty::Binder::dummy(vec![])),
+        },
+
+        // impl {} for extern type
+        ty::Foreign(..) => Err(NoSolution),
+
+        ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => Err(NoSolution),
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
@@ -150,22 +156,27 @@ where
 
         ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
 
-        // impl Sized for ()
-        // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1
+        // impl {Meta,}Sized for ()
+        // impl {Meta,}Sized for (T1, T2, .., Tn) where Tn: {Meta,}Sized if n >= 1
         ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.last().map_or_else(Vec::new, |ty| vec![ty]))),
 
-        // impl Sized for Adt<Args...> where sized_constraint(Adt)<Args...>: Sized
-        //   `sized_constraint(Adt)` is the deepest struct trail that can be determined
-        //   by the definition of `Adt`, independent of the generic args.
-        // impl Sized for Adt<Args...> if sized_constraint(Adt) == None
-        //   As a performance optimization, `sized_constraint(Adt)` can return `None`
-        //   if the ADTs definition implies that it is sized by for all possible args.
+        // impl {Meta,}Sized for Adt<Args...>
+        //   where {meta,pointee,}sized_constraint(Adt)<Args...>: {Meta,}Sized
+        //
+        //   `{meta,pointee,}sized_constraint(Adt)` is the deepest struct trail that can be
+        //   determined by the definition of `Adt`, independent of the generic args.
+        //
+        // impl {Meta,}Sized for Adt<Args...>
+        //   if {meta,pointee,}sized_constraint(Adt) == None
+        //
+        //   As a performance optimization, `{meta,pointee,}sized_constraint(Adt)` can return `None`
+        //   if the ADTs definition implies that it is {meta,}sized by for all possible args.
         //   In this case, the builtin impl will have no nested subgoals. This is a
-        //   "best effort" optimization and `sized_constraint` may return `Some`, even
-        //   if the ADT is sized for all possible args.
+        //   "best effort" optimization and `{meta,pointee,}sized_constraint` may return `Some`,
+        //   even if the ADT is {meta,pointee,}sized for all possible args.
         ty::Adt(def, args) => {
-            if let Some(sized_crit) = def.sized_constraint(ecx.cx()) {
-                Ok(ty::Binder::dummy(vec![sized_crit.instantiate(ecx.cx(), args)]))
+            if let Some(crit) = def.sizedness_constraint(ecx.cx(), sizedness) {
+                Ok(ty::Binder::dummy(vec![crit.instantiate(ecx.cx(), args)]))
             } else {
                 Ok(ty::Binder::dummy(vec![]))
             }
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index dda00a0a2c5..1690c908d12 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -4,6 +4,7 @@
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::solve::inspect::ProbeKind;
 use rustc_type_ir::{self as ty, Interner, elaborate};
 use tracing::instrument;
@@ -198,25 +199,12 @@ where
         unreachable!("trait aliases are never const")
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
+        _sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("Sized is never const")
-    }
-
-    fn consider_builtin_meta_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("MetaSized is never const")
-    }
-
-    fn consider_builtin_pointee_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("PointeeSized is never const")
+        unreachable!("Sized/MetaSized is never const")
     }
 
     fn consider_builtin_copy_clone_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 42aeb170d6b..d51c87fe68e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -6,6 +6,7 @@ mod opaque_types;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
 use tracing::instrument;
 
@@ -413,25 +414,12 @@ where
         panic!("trait aliases do not have associated types: {:?}", goal);
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         _ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        _sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`Sized` does not have an associated type: {:?}", goal);
-    }
-
-    fn consider_builtin_meta_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`MetaSized` does not have an associated type: {:?}", goal);
-    }
-
-    fn consider_builtin_pointee_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`PointeeSized` does not have an associated type: {:?}", goal);
+        panic!("`Sized`/`MetaSized` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_copy_clone_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 50a7647be62..a8bbc2d60f1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -4,7 +4,7 @@ use rustc_type_ir::data_structures::IndexSet;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::solve::CanonicalResponse;
+use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
 use rustc_type_ir::{
     self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
     Upcast as _, elaborate,
@@ -245,9 +245,10 @@ where
         })
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
@@ -256,37 +257,11 @@ where
         ecx.probe_and_evaluate_goal_for_constituent_tys(
             CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
             goal,
-            structural_traits::instantiate_constituent_tys_for_sized_trait,
-        )
-    }
-
-    fn consider_builtin_meta_sized_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        ecx.probe_and_evaluate_goal_for_constituent_tys(
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
-            goal,
-            structural_traits::instantiate_constituent_tys_for_sized_trait,
-        )
-    }
-
-    fn consider_builtin_pointee_sized_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        ecx.probe_and_evaluate_goal_for_constituent_tys(
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
-            goal,
-            structural_traits::instantiate_constituent_tys_for_sized_trait,
+            |ecx, ty| {
+                structural_traits::instantiate_constituent_tys_for_sizedness_trait(
+                    ecx, sizedness, ty,
+                )
+            },
         )
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 93ffea3b031..b7be73a3c2b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
 use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate};
+use rustc_middle::ty::{self, SizedTraitKind, Ty, TypeVisitableExt, TypingMode, elaborate};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
@@ -87,13 +87,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     candidates.vec.push(BuiltinCandidate { has_nested: false });
                 }
                 Some(LangItem::Sized) => {
-                    self.assemble_builtin_sized_candidate(obligation, &mut candidates);
+                    self.assemble_builtin_sized_candidate(
+                        obligation,
+                        &mut candidates,
+                        SizedTraitKind::Sized,
+                    );
                 }
                 Some(LangItem::MetaSized) => {
-                    self.assemble_builtin_sized_candidate(obligation, &mut candidates);
+                    self.assemble_builtin_sized_candidate(
+                        obligation,
+                        &mut candidates,
+                        SizedTraitKind::MetaSized,
+                    );
                 }
                 Some(LangItem::PointeeSized) => {
-                    self.assemble_builtin_sized_candidate(obligation, &mut candidates);
+                    bug!("`PointeeSized` is removed during lowering");
                 }
                 Some(LangItem::Unsize) => {
                     self.assemble_candidates_for_unsizing(obligation, &mut candidates);
@@ -1092,15 +1100,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    /// Assembles the trait which are built-in to the language itself:
-    /// `Copy`, `Clone` and `Sized`.
+    /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
     #[instrument(level = "debug", skip(self, candidates))]
     fn assemble_builtin_sized_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
+        sizedness: SizedTraitKind,
     ) {
-        match self.sized_conditions(obligation) {
+        match self.sizedness_conditions(obligation, sizedness) {
             BuiltinImplConditions::Where(nested) => {
                 candidates
                     .vec
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 93d3e3ba2a8..b2d2f1188c3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,7 +14,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate};
+use rustc_middle::ty::{
+    self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use thin_vec::thin_vec;
@@ -251,9 +253,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let obligations = if has_nested {
             let trait_def = obligation.predicate.def_id();
             let conditions = match tcx.as_lang_item(trait_def) {
-                Some(LangItem::Sized) => self.sized_conditions(obligation),
-                Some(LangItem::MetaSized) => self.sized_conditions(obligation),
-                Some(LangItem::PointeeSized) => self.sized_conditions(obligation),
+                Some(LangItem::Sized) => {
+                    self.sizedness_conditions(obligation, SizedTraitKind::Sized)
+                }
+                Some(LangItem::MetaSized) => {
+                    self.sizedness_conditions(obligation, SizedTraitKind::MetaSized)
+                }
+                Some(LangItem::PointeeSized) => {
+                    bug!("`PointeeSized` is removing during lowering");
+                }
                 Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation),
                 Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation),
                 other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1b9b68fa980..9c0ccb26e53 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -27,8 +27,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, TypingMode, Upcast, elaborate,
+    self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
+    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
 };
 use rustc_span::{Symbol, sym};
 use tracing::{debug, instrument, trace};
@@ -2094,9 +2094,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 }
 
 impl<'tcx> SelectionContext<'_, 'tcx> {
-    fn sized_conditions(
+    fn sizedness_conditions(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
+        sizedness: SizedTraitKind,
     ) -> BuiltinImplConditions<'tcx> {
         use self::BuiltinImplConditions::{Ambiguous, None, Where};
 
@@ -2126,7 +2127,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 Where(ty::Binder::dummy(Vec::new()))
             }
 
-            ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
+            ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
+                SizedTraitKind::Sized => None,
+                SizedTraitKind::MetaSized => Where(ty::Binder::dummy(Vec::new())),
+            },
+
+            ty::Foreign(..) => None,
 
             ty::Tuple(tys) => Where(
                 obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
@@ -2135,11 +2141,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
 
             ty::Adt(def, args) => {
-                if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
+                if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) {
                     // (*) binder moved here
-                    Where(
-                        obligation.predicate.rebind(vec![sized_crit.instantiate(self.tcx(), args)]),
-                    )
+                    Where(obligation.predicate.rebind(vec![crit.instantiate(self.tcx(), args)]))
                 } else {
                     Where(ty::Binder::dummy(Vec::new()))
                 }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 11becea998c..923c9242ff8 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,23 +1,29 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::LangItem;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions,
+    self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
+    fold_regions,
 };
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_trait_selection::traits;
 use tracing::instrument;
 
+/// If `ty` implements the given `sizedness` trait, returns `None`. Otherwise, returns the type
+/// that must implement the given `sizedness` for `ty` to implement it.
 #[instrument(level = "debug", skip(tcx), ret)]
-fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+fn sizedness_constraint_for_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sizedness: SizedTraitKind,
+    ty: Ty<'tcx>,
+) -> Option<Ty<'tcx>> {
     match ty.kind() {
-        // these are always sized
+        // Always `Sized` or `MetaSized`
         ty::Bool
         | ty::Char
         | ty::Int(..)
@@ -35,31 +41,40 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
         | ty::Never
         | ty::Dynamic(_, _, ty::DynStar) => None,
 
-        // these are never sized
-        ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => Some(ty),
-
-        ty::Pat(ty, _) => sized_constraint_for_ty(tcx, *ty),
-
-        ty::Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
-
-        // recursive case
-        ty::Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| {
-            let ty = intermediate.instantiate(tcx, args);
-            sized_constraint_for_ty(tcx, ty)
-        }),
+        ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
+            // Never `Sized`
+            SizedTraitKind::Sized => Some(ty),
+            // Always `MetaSized`
+            SizedTraitKind::MetaSized => None,
+        },
 
-        // these can be sized or unsized.
+        // Maybe `Sized` or `MetaSized`
         ty::Param(..) | ty::Alias(..) | ty::Error(_) => Some(ty),
 
         // We cannot instantiate the binder, so just return the *original* type back,
         // but only if the inner type has a sized constraint. Thus we skip the binder,
         // but don't actually use the result from `sized_constraint_for_ty`.
         ty::UnsafeBinder(inner_ty) => {
-            sized_constraint_for_ty(tcx, inner_ty.skip_binder()).map(|_| ty)
+            sizedness_constraint_for_ty(tcx, sizedness, inner_ty.skip_binder()).map(|_| ty)
+        }
+
+        // Never `MetaSized` or `Sized`
+        ty::Foreign(..) => Some(ty),
+
+        // Recursive cases
+        ty::Pat(ty, _) => sizedness_constraint_for_ty(tcx, sizedness, *ty),
+
+        ty::Tuple(tys) => {
+            tys.last().and_then(|&ty| sizedness_constraint_for_ty(tcx, sizedness, ty))
         }
 
+        ty::Adt(adt, args) => adt.sizedness_constraint(tcx, sizedness).and_then(|intermediate| {
+            let ty = intermediate.instantiate(tcx, args);
+            sizedness_constraint_for_ty(tcx, sizedness, ty)
+        }),
+
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
-            bug!("unexpected type `{ty:?}` in sized_constraint_for_ty")
+            bug!("unexpected type `{ty:?}` in `sizedness_constraint_for_ty`")
         }
     }
 }
@@ -75,15 +90,22 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
     }
 }
 
-/// Calculates the `Sized` constraint.
+/// Returns the type of the last field of a struct ("the constraint") which must implement the
+/// `sizedness` trait for the whole ADT to be considered to implement that `sizedness` trait.
+/// `def_id` is assumed to be the `AdtDef` of a struct and will panic otherwise.
+///
+/// For `Sized`, there are only a few options for the types in the constraint:
+///     - an metasized type (str, slices, trait objects, etc)
+///     - an pointee-sized type (extern types)
+///     - a type parameter or projection whose sizedness can't be known
 ///
-/// In fact, there are only a few options for the types in the constraint:
-///     - an obviously-unsized type
+/// For `MetaSized`, there are only a few options for the types in the constraint:
+///     - an pointee-sized type (extern types)
 ///     - a type parameter or projection whose sizedness can't be known
 #[instrument(level = "debug", skip(tcx), ret)]
-fn adt_sized_constraint<'tcx>(
+fn adt_sizedness_constraint<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    (def_id, sizedness): (DefId, SizedTraitKind),
 ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
     if let Some(def_id) = def_id.as_local() {
         if let ty::Representability::Infinite(_) = tcx.representability(def_id) {
@@ -93,21 +115,21 @@ fn adt_sized_constraint<'tcx>(
     let def = tcx.adt_def(def_id);
 
     if !def.is_struct() {
-        bug!("`adt_sized_constraint` called on non-struct type: {def:?}");
+        bug!("`adt_sizedness_constraint` called on non-struct type: {def:?}");
     }
 
     let tail_def = def.non_enum_variant().tail_opt()?;
     let tail_ty = tcx.type_of(tail_def.did).instantiate_identity();
 
-    let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?;
+    let constraint_ty = sizedness_constraint_for_ty(tcx, sizedness, tail_ty)?;
 
-    // perf hack: if there is a `constraint_ty: Sized` bound, then we know
+    // perf hack: if there is a `constraint_ty: {Meta,}Sized` bound, then we know
     // that the type is sized and do not need to check it on the impl.
-    let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+    let sizedness_trait_def_id = sizedness.require_lang_item(tcx);
     let predicates = tcx.predicates_of(def.did()).predicates;
     if predicates.iter().any(|(p, _)| {
         p.as_trait_clause().is_some_and(|trait_pred| {
-            trait_pred.def_id() == sized_trait_def_id
+            trait_pred.def_id() == sizedness_trait_def_id
                 && trait_pred.self_ty().skip_binder() == constraint_ty
         })
     }) {
@@ -369,7 +391,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         asyncness,
-        adt_sized_constraint,
+        adt_sizedness_constraint,
         param_env,
         typing_env_normalized_for_post_analysis,
         defaultness,
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 436ab9f80b6..608efc7515c 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -11,7 +11,7 @@ use rustc_ast_ir::Mutability;
 use crate::elaborate::Elaboratable;
 use crate::fold::{TypeFoldable, TypeSuperFoldable};
 use crate::relate::Relate;
-use crate::solve::AdtDestructorKind;
+use crate::solve::{AdtDestructorKind, SizedTraitKind};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
 
@@ -571,7 +571,11 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
     // FIXME: perhaps use `all_fields` and expose `FieldDef`.
     fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
 
-    fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
+    fn sizedness_constraint(
+        self,
+        interner: I,
+        sizedness: SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<I, I::Ty>>;
 
     fn is_fundamental(self) -> bool;
 
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index ba777c7c59a..bbbeaa29f84 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -8,6 +8,7 @@ use derive_where::derive_where;
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
+use crate::lang_items::TraitSolverLangItem;
 use crate::search_graph::PathKind;
 use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
 
@@ -366,3 +367,24 @@ pub enum AdtDestructorKind {
     NotConst,
     Const,
 }
+
+/// Which sizedness trait - `Sized`, `MetaSized`? `PointeeSized` is omitted as it is removed during
+/// lowering.
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum SizedTraitKind {
+    /// `Sized` trait
+    Sized,
+    /// `MetaSized` trait
+    MetaSized,
+}
+
+impl SizedTraitKind {
+    /// Returns `DefId` of corresponding language item.
+    pub fn require_lang_item<I: Interner>(self, cx: I) -> I::DefId {
+        cx.require_lang_item(match self {
+            SizedTraitKind::Sized => TraitSolverLangItem::Sized,
+            SizedTraitKind::MetaSized => TraitSolverLangItem::MetaSized,
+        })
+    }
+}
diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr
index fe662dd48f4..7db2abc5ffe 100644
--- a/tests/ui/attributes/dump-preds.stderr
+++ b/tests/ui/attributes/dump-preds.stderr
@@ -35,6 +35,7 @@ LL |     type Assoc<P: Eq>: std::ops::Deref<Target = ()>
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::ops::Deref>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::Sized>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::MetaSized>, polarity:Positive), bound_vars: [] }
+   = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::PointeeSized>, polarity:Positive), bound_vars: [] }
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs b/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs
index bc81a7e6c38..5e2a76ba254 100644
--- a/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs
+++ b/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs
@@ -13,9 +13,7 @@ fn main() {
     needs_sized::<u8>();
 
     needs_pointeesized::<str>();
-//~^ ERROR values of type `str` may or may not have a size
     needs_metasized::<str>();
-//~^ ERROR the size for values of type `str` cannot be known
     needs_sized::<str>();
 //~^ ERROR the size for values of type `str` cannot be known at compilation time
 
@@ -24,7 +22,6 @@ fn main() {
     }
 
     needs_pointeesized::<Foo>();
-//~^ ERROR values of type `main::Foo` may or may not have a size
     needs_metasized::<Foo>();
 //~^ ERROR the size for values of type `main::Foo` cannot be known
     needs_sized::<Foo>();
diff --git a/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr
index 64f544c5d8f..8cbea3b6ba4 100644
--- a/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr
+++ b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr
@@ -1,31 +1,5 @@
-error[E0277]: values of type `str` may or may not have a size
-  --> $DIR/feature-gate-sized-hierarchy.rs:15:26
-   |
-LL |     needs_pointeesized::<str>();
-   |                          ^^^ may or may not have a known size
-   |
-   = help: the trait `PointeeSized` is not implemented for `str`
-note: required by a bound in `needs_pointeesized`
-  --> $DIR/feature-gate-sized-hierarchy.rs:6:35
-   |
-LL | fn needs_pointeesized<T: ?Sized + PointeeSized>() {}
-   |                                   ^^^^^^^^^^^^ required by this bound in `needs_pointeesized`
-
-error[E0277]: the size for values of type `str` cannot be known
-  --> $DIR/feature-gate-sized-hierarchy.rs:17:23
-   |
-LL |     needs_metasized::<str>();
-   |                       ^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `str`
-note: required by a bound in `needs_metasized`
-  --> $DIR/feature-gate-sized-hierarchy.rs:7:32
-   |
-LL | fn needs_metasized<T: ?Sized + MetaSized>() {}
-   |                                ^^^^^^^^^ required by this bound in `needs_metasized`
-
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/feature-gate-sized-hierarchy.rs:19:19
+  --> $DIR/feature-gate-sized-hierarchy.rs:17:19
    |
 LL |     needs_sized::<str>();
    |                   ^^^ doesn't have a size known at compile-time
@@ -37,21 +11,8 @@ note: required by a bound in `needs_sized`
 LL | fn needs_sized<T: Sized>() {}
    |                   ^^^^^ required by this bound in `needs_sized`
 
-error[E0277]: values of type `main::Foo` may or may not have a size
-  --> $DIR/feature-gate-sized-hierarchy.rs:26:26
-   |
-LL |     needs_pointeesized::<Foo>();
-   |                          ^^^ may or may not have a known size
-   |
-   = help: the trait `PointeeSized` is not implemented for `main::Foo`
-note: required by a bound in `needs_pointeesized`
-  --> $DIR/feature-gate-sized-hierarchy.rs:6:35
-   |
-LL | fn needs_pointeesized<T: ?Sized + PointeeSized>() {}
-   |                                   ^^^^^^^^^^^^ required by this bound in `needs_pointeesized`
-
 error[E0277]: the size for values of type `main::Foo` cannot be known
-  --> $DIR/feature-gate-sized-hierarchy.rs:28:23
+  --> $DIR/feature-gate-sized-hierarchy.rs:25:23
    |
 LL |     needs_metasized::<Foo>();
    |                       ^^^ doesn't have a known size
@@ -64,7 +25,7 @@ LL | fn needs_metasized<T: ?Sized + MetaSized>() {}
    |                                ^^^^^^^^^ required by this bound in `needs_metasized`
 
 error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
-  --> $DIR/feature-gate-sized-hierarchy.rs:30:19
+  --> $DIR/feature-gate-sized-hierarchy.rs:27:19
    |
 LL |     needs_sized::<Foo>();
    |                   ^^^ doesn't have a size known at compile-time
@@ -76,6 +37,6 @@ note: required by a bound in `needs_sized`
 LL | fn needs_sized<T: Sized>() {}
    |                   ^^^^^ required by this bound in `needs_sized`
 
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/impls.rs b/tests/ui/sized-hierarchy/impls.rs
new file mode 100644
index 00000000000..b05313dccae
--- /dev/null
+++ b/tests/ui/sized-hierarchy/impls.rs
@@ -0,0 +1,307 @@
+//@ check-fail
+//@ edition:2021
+#![allow(incomplete_features, internal_features)]
+#![feature(sized_hierarchy)]
+#![feature(coroutines, dyn_star, extern_types, f16, never_type, unsized_fn_params)]
+use std::fmt::Debug;
+use std::marker::{MetaSized, PointeeSized};
+
+// This test checks that `Sized` and `MetaSized` are automatically implemented appropriately.
+
+fn needs_sized<T: Sized>() { }
+fn takes_sized<T: Sized>(_t: T) { }
+
+fn needs_metasized<T: ?Sized + MetaSized>() { }
+fn takes_metasized<T: ?Sized + MetaSized>(_t: T) { }
+
+fn needs_pointeesized<T: ?Sized + PointeeSized>() { }
+fn takes_pointeesized<T: ?Sized + PointeeSized>(_t: T) { }
+
+fn main() {
+    // `bool`
+    needs_sized::<bool>();
+    needs_metasized::<bool>();
+    needs_pointeesized::<bool>();
+
+    // `char`
+    needs_sized::<char>();
+    needs_metasized::<char>();
+    needs_pointeesized::<char>();
+
+    // `i8`
+    needs_sized::<i8>();
+    needs_metasized::<i8>();
+    needs_pointeesized::<i8>();
+
+    // `i16`
+    needs_sized::<i16>();
+    needs_metasized::<i16>();
+    needs_pointeesized::<i16>();
+
+    // `i32`
+    needs_sized::<i32>();
+    needs_metasized::<i32>();
+    needs_pointeesized::<i32>();
+
+    // `i64`
+    needs_sized::<i64>();
+    needs_metasized::<i64>();
+    needs_pointeesized::<i64>();
+
+    // `i128`
+    needs_sized::<i128>();
+    needs_metasized::<i128>();
+    needs_pointeesized::<i128>();
+
+    // `u8`
+    needs_sized::<u8>();
+    needs_metasized::<u8>();
+    needs_pointeesized::<u8>();
+
+    // `u16`
+    needs_sized::<u16>();
+    needs_metasized::<u16>();
+    needs_pointeesized::<u16>();
+
+    // `u32`
+    needs_sized::<u32>();
+    needs_metasized::<u32>();
+    needs_pointeesized::<u32>();
+
+    // `u64`
+    needs_sized::<u64>();
+    needs_metasized::<u64>();
+    needs_pointeesized::<u64>();
+
+    // `u128`
+    needs_sized::<u128>();
+    needs_metasized::<u128>();
+    needs_pointeesized::<u128>();
+
+    // `f16`
+    needs_sized::<f16>();
+    needs_metasized::<f16>();
+    needs_pointeesized::<f16>();
+
+    // `f32`
+    needs_sized::<f32>();
+    needs_metasized::<f32>();
+    needs_pointeesized::<f32>();
+
+    // `f64`
+    needs_sized::<f64>();
+    needs_metasized::<f64>();
+    needs_pointeesized::<f64>();
+
+    // `*const`
+    needs_sized::<*const u8>();
+    needs_metasized::<*const u8>();
+    needs_pointeesized::<*const u8>();
+
+    // `*mut`
+    needs_sized::<*mut u8>();
+    needs_metasized::<*mut u8>();
+    needs_pointeesized::<*mut u8>();
+
+    // `&`
+    needs_sized::<&u8>();
+    needs_metasized::<&u8>();
+    needs_pointeesized::<&u8>();
+
+    // `&mut`
+    needs_sized::<&mut u8>();
+    needs_metasized::<&mut u8>();
+    needs_pointeesized::<&mut u8>();
+
+    // fn-def
+    fn foo(x: u8) -> u8 { x }
+    takes_sized(foo);
+    takes_metasized(foo);
+    takes_pointeesized(foo);
+
+    // fn-ptr
+    takes_sized::<fn(u8) -> u8>(foo);
+    takes_metasized::<fn(u8) -> u8>(foo);
+    takes_pointeesized::<fn(u8) -> u8>(foo);
+
+    // `[T; x]`
+    needs_sized::<[u8; 1]>();
+    needs_metasized::<[u8; 1]>();
+    needs_pointeesized::<[u8; 1]>();
+
+    // `|a| { a }`
+    takes_sized(|a| { a });
+    takes_metasized(|a| { a });
+    takes_pointeesized(|a| { a });
+
+    // `async |a| { a }`
+    takes_sized(async |a| { a });
+    takes_metasized(async |a| { a });
+    takes_pointeesized(async |a| { a });
+
+    // `|a| { yield a }`
+    takes_sized(#[coroutine] |a| { yield a });
+    takes_metasized(#[coroutine] |a| { yield a });
+    takes_pointeesized(#[coroutine] |a| { yield a });
+
+    // `!`
+    needs_sized::<!>();
+    needs_metasized::<!>();
+    needs_pointeesized::<!>();
+
+    // `dyn*`
+    needs_sized::<dyn* Debug>();
+    needs_metasized::<dyn* Debug>();
+    needs_pointeesized::<dyn* Debug>();
+
+    // `str`
+    needs_sized::<str>();
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    needs_metasized::<str>();
+    needs_pointeesized::<str>();
+
+    // `[T]`
+    needs_sized::<[u8]>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<[u8]>();
+    needs_pointeesized::<[u8]>();
+
+    // `dyn Debug`
+    needs_sized::<dyn Debug>();
+    //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time
+    needs_metasized::<dyn Debug>();
+    needs_pointeesized::<dyn Debug>();
+
+    // `extern type`
+    extern "C" {
+        type Foo;
+    }
+    needs_sized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<Foo>();
+
+    // empty tuple
+    needs_sized::<()>();
+    needs_metasized::<()>();
+    needs_pointeesized::<()>();
+
+    // tuple w/ all elements sized
+    needs_sized::<(u32, u32)>();
+    needs_metasized::<(u32, u32)>();
+    needs_pointeesized::<(u32, u32)>();
+
+    // tuple w/ all elements metasized
+    needs_sized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_pointeesized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+    // tuple w/ all elements pointeesized
+    needs_sized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_pointeesized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+
+    // tuple w/ last element metasized
+    needs_sized::<(u32, [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<(u32, [u8])>();
+    needs_pointeesized::<(u32, [u8])>();
+
+    // tuple w/ last element pointeesized
+    needs_sized::<(u32, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<(u32, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<(u32, Foo)>();
+
+    // struct w/ no fields
+    struct StructEmpty {}
+    needs_sized::<StructEmpty>();
+    needs_metasized::<StructEmpty>();
+    needs_pointeesized::<StructEmpty>();
+
+    // struct w/ all fields sized
+    struct StructAllFieldsSized { x: u32, y: u32 }
+    needs_sized::<StructAllFieldsSized>();
+    needs_metasized::<StructAllFieldsSized>();
+    needs_pointeesized::<StructAllFieldsSized>();
+
+    // struct w/ all fields metasized
+    struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<StructAllFieldsMetaSized>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<StructAllFieldsMetaSized>();
+    needs_pointeesized::<StructAllFieldsMetaSized>();
+
+    // struct w/ all fields unsized
+    struct StructAllFieldsUnsized { x: Foo, y: Foo }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<StructAllFieldsUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<StructAllFieldsUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<StructAllFieldsUnsized>();
+
+    // struct w/ last fields metasized
+    struct StructLastFieldMetaSized { x: u32, y: [u8] }
+    needs_sized::<StructLastFieldMetaSized>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<StructLastFieldMetaSized>();
+    needs_pointeesized::<StructLastFieldMetaSized>();
+
+    // struct w/ last fields unsized
+    struct StructLastFieldUnsized { x: u32, y: Foo }
+    needs_sized::<StructLastFieldUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<StructLastFieldUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<StructLastFieldUnsized>();
+
+    // enum w/ no fields
+    enum EnumEmpty {}
+    needs_sized::<EnumEmpty>();
+    needs_metasized::<EnumEmpty>();
+    needs_pointeesized::<EnumEmpty>();
+
+    // enum w/ all variant fields sized
+    enum EnumAllFieldsSized { Qux { x: u32, y: u32 } }
+    needs_sized::<StructAllFieldsSized>();
+    needs_metasized::<StructAllFieldsSized>();
+    needs_pointeesized::<StructAllFieldsSized>();
+
+    // enum w/ all variant fields metasized
+    enum EnumAllFieldsMetaSized { Qux { x: [u8], y: [u8] } }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<EnumAllFieldsMetaSized>();
+    needs_metasized::<EnumAllFieldsMetaSized>();
+    needs_pointeesized::<EnumAllFieldsMetaSized>();
+
+    // enum w/ all variant fields unsized
+    enum EnumAllFieldsUnsized { Qux { x: Foo, y: Foo } }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<EnumAllFieldsUnsized>();
+    needs_metasized::<EnumAllFieldsUnsized>();
+    needs_pointeesized::<EnumAllFieldsUnsized>();
+
+    // enum w/ last variant fields metasized
+    enum EnumLastFieldMetaSized { Qux { x: u32, y: [u8] } }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<EnumLastFieldMetaSized>();
+    needs_metasized::<EnumLastFieldMetaSized>();
+    needs_pointeesized::<EnumLastFieldMetaSized>();
+
+    // enum w/ last variant fields unsized
+    enum EnumLastFieldUnsized { Qux { x: u32, y: Foo } }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<EnumLastFieldUnsized>();
+    needs_metasized::<EnumLastFieldUnsized>();
+    needs_pointeesized::<EnumLastFieldUnsized>();
+}
diff --git a/tests/ui/sized-hierarchy/impls.stderr b/tests/ui/sized-hierarchy/impls.stderr
new file mode 100644
index 00000000000..5fffe478663
--- /dev/null
+++ b/tests/ui/sized-hierarchy/impls.stderr
@@ -0,0 +1,380 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:237:42
+   |
+LL |     struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+   |                                          ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     struct StructAllFieldsMetaSized { x: &[u8], y: [u8] }
+   |                                          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     struct StructAllFieldsMetaSized { x: Box<[u8]>, y: [u8] }
+   |                                          ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:245:40
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |                                        ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     struct StructAllFieldsUnsized { x: &Foo, y: Foo }
+   |                                        +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     struct StructAllFieldsUnsized { x: Box<Foo>, y: Foo }
+   |                                        ++++   +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:281:44
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: [u8], y: [u8] } }
+   |                                            ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: &[u8], y: [u8] } }
+   |                                            +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: Box<[u8]>, y: [u8] } }
+   |                                            ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:288:42
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: Foo, y: Foo } }
+   |                                          ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: &Foo, y: Foo } }
+   |                                          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: Box<Foo>, y: Foo } }
+   |                                          ++++   +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:295:52
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: [u8] } }
+   |                                                    ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: &[u8] } }
+   |                                                    +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: Box<[u8]> } }
+   |                                                    ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:302:50
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: Foo } }
+   |                                                  ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: &Foo } }
+   |                                                  +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: Box<Foo> } }
+   |                                                  ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/impls.rs:158:19
+   |
+LL |     needs_sized::<str>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:164:19
+   |
+LL |     needs_sized::<[u8]>();
+   |                   ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
+  --> $DIR/impls.rs:170:19
+   |
+LL |     needs_sized::<dyn Debug>();
+   |                   ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Debug`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:179:19
+   |
+LL |     needs_sized::<Foo>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:181:23
+   |
+LL |     needs_metasized::<Foo>();
+   |                       ^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `main::Foo`
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:14:32
+   |
+LL | fn needs_metasized<T: ?Sized + MetaSized>() { }
+   |                                ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:196:19
+   |
+LL |     needs_sized::<([u8], [u8])>();
+   |                   ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:198:23
+   |
+LL |     needs_metasized::<([u8], [u8])>();
+   |                       ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:200:26
+   |
+LL |     needs_pointeesized::<([u8], [u8])>();
+   |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:204:19
+   |
+LL |     needs_sized::<(Foo, Foo)>();
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:206:23
+   |
+LL |     needs_metasized::<(Foo, Foo)>();
+   |                       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:208:26
+   |
+LL |     needs_pointeesized::<(Foo, Foo)>();
+   |                          ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:212:19
+   |
+LL |     needs_sized::<(u32, [u8])>();
+   |                   ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(u32, [u8])`, the trait `Sized` is not implemented for `[u8]`
+   = note: required because it appears within the type `(u32, [u8])`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:218:19
+   |
+LL |     needs_sized::<(u32, Foo)>();
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(u32, main::Foo)`, the trait `Sized` is not implemented for `main::Foo`
+   = note: required because it appears within the type `(u32, main::Foo)`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:220:23
+   |
+LL |     needs_metasized::<(u32, Foo)>();
+   |                       ^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `(u32, main::Foo)`, the trait `MetaSized` is not implemented for `main::Foo`
+   = note: required because it appears within the type `(u32, main::Foo)`
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:14:32
+   |
+LL | fn needs_metasized<T: ?Sized + MetaSized>() { }
+   |                                ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:239:19
+   |
+LL |     needs_sized::<StructAllFieldsMetaSized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructAllFieldsMetaSized`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `StructAllFieldsMetaSized`
+  --> $DIR/impls.rs:237:12
+   |
+LL |     struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:247:19
+   |
+LL |     needs_sized::<StructAllFieldsUnsized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructAllFieldsUnsized`, the trait `Sized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructAllFieldsUnsized`
+  --> $DIR/impls.rs:245:12
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:249:23
+   |
+LL |     needs_metasized::<StructAllFieldsUnsized>();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `StructAllFieldsUnsized`, the trait `MetaSized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructAllFieldsUnsized`
+  --> $DIR/impls.rs:245:12
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:14:32
+   |
+LL | fn needs_metasized<T: ?Sized + MetaSized>() { }
+   |                                ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:255:19
+   |
+LL |     needs_sized::<StructLastFieldMetaSized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructLastFieldMetaSized`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `StructLastFieldMetaSized`
+  --> $DIR/impls.rs:254:12
+   |
+LL |     struct StructLastFieldMetaSized { x: u32, y: [u8] }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:262:19
+   |
+LL |     needs_sized::<StructLastFieldUnsized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructLastFieldUnsized`, the trait `Sized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructLastFieldUnsized`
+  --> $DIR/impls.rs:261:12
+   |
+LL |     struct StructLastFieldUnsized { x: u32, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:11:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:264:23
+   |
+LL |     needs_metasized::<StructLastFieldUnsized>();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `StructLastFieldUnsized`, the trait `MetaSized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructLastFieldUnsized`
+  --> $DIR/impls.rs:261:12
+   |
+LL |     struct StructLastFieldUnsized { x: u32, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:14:32
+   |
+LL | fn needs_metasized<T: ?Sized + MetaSized>() { }
+   |                                ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error: aborting due to 26 previous errors
+
+For more information about this error, try `rustc --explain E0277`.