about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorDavid Wood <david.wood2@arm.com>2025-02-27 21:19:51 +0000
committerDavid Wood <david.wood2@arm.com>2025-06-16 23:04:33 +0000
commit86ab2b60cd22f6190eb586c889f8a2504f0d926b (patch)
treec379a930de63e5cb21b83110dccd82c1c3874a25 /compiler
parentf0b84b8dcfc15c3936256ccb438b1d050620ff3c (diff)
hir_analysis: add `{Meta,Pointee}Sized` bounds
Opting-out of `Sized` with `?Sized` is now equivalent to adding a
`MetaSized` bound, and adding a `MetaSized` or `PointeeSized` bound
is equivalent to removing the default `Sized` bound - this commit
implements this change in `rustc_hir_analysis::hir_ty_lowering`.

`MetaSized` is also added as a supertrait of all traits, as this is
necessary to preserve backwards compatibility.

Unfortunately, non-global where clauses being preferred over item bounds
(where `PointeeSized` bounds would be proven) - which can result in
errors when a `PointeeSized` supertrait/bound/predicate is added to some
items. Rather than `PointeeSized` being a bound on everything, it can
be the absence of a bound on everything, as `?Sized` was.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs346
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs53
-rw-r--r--compiler/rustc_middle/src/ty/context.rs11
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
8 files changed, 323 insertions, 142 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index c5c7e6b2aa7..5b8aa28102c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -76,6 +76,7 @@ pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
 use rustc_abi::{ExternAbi, VariantIdx};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
+use rustc_hir::LangItem;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::DenseBitSet;
@@ -331,7 +332,7 @@ fn bounds_from_generic_predicates<'tcx>(
             ty::ClauseKind::Trait(trait_predicate) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
-                if !tcx.is_default_trait(def_id) {
+                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
                     // Do not add that restriction to the list if it is a positive requirement.
                     entry.push(trait_predicate.def_id());
                 }
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 5f1cdeddc19..53c44cdc411 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -44,6 +44,14 @@ fn associated_type_bounds<'tcx>(
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    item_ty,
+                    hir_bounds,
+                    None,
+                    None,
+                    span,
+                );
                 icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             // `ConstIfConst` is only interested in `~const` bounds.
@@ -333,6 +341,14 @@ fn opaque_type_bounds<'tcx>(
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    item_ty,
+                    hir_bounds,
+                    None,
+                    None,
+                    span,
+                );
                 icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             //`ConstIfConst` is only interested in `~const` bounds.
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ce0f83d0ec2..c337765c5fe 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -162,7 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                         .map(|t| ty::Binder::dummy(t.instantiate_identity()));
                 }
             }
-
             ItemKind::Trait(_, _, _, _, self_bounds, ..)
             | ItemKind::TraitAlias(_, _, self_bounds) => {
                 is_trait = Some((self_bounds, item.span));
@@ -183,21 +182,29 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // and the explicit where-clauses, but to get the full set of predicates
     // on a trait we must also consider the bounds that follow the trait's name,
     // like `trait Foo: A + B + C`.
-    if let Some(self_bounds) = is_trait {
+    if let Some((self_bounds, span)) = is_trait {
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
-            self_bounds.0,
+            self_bounds,
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::All,
         );
+        icx.lowerer().add_sizedness_bounds(
+            &mut bounds,
+            tcx.types.self_param,
+            self_bounds,
+            None,
+            Some(def_id),
+            span,
+        );
         icx.lowerer().add_default_super_traits(
             def_id,
             &mut bounds,
-            self_bounds.0,
+            self_bounds,
             hir_generics,
-            self_bounds.1,
+            span,
         );
         predicates.extend(bounds);
     }
@@ -224,6 +231,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
                 let mut bounds = Vec::new();
                 // Implicit bounds are added to type params unless a `?Trait` bound is found
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    param_ty,
+                    &[],
+                    Some((param.def_id, hir_generics.predicates)),
+                    None,
+                    param.span,
+                );
                 icx.lowerer().add_default_traits(
                     &mut bounds,
                     param_ty,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 106420faa4c..ea1dfdfd806 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -4,15 +4,15 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
-use rustc_hir::AmbigArg;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
     TypeVisitor, Upcast,
 };
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw};
 use rustc_trait_selection::traits;
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
@@ -23,23 +23,213 @@ use crate::hir_ty_lowering::{
     AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
 };
 
+#[derive(Debug, Default)]
+struct CollectedBound {
+    /// `Trait`
+    positive: bool,
+    /// `?Trait`
+    maybe: bool,
+    /// `!Trait`
+    negative: bool,
+}
+
+impl CollectedBound {
+    /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
+    fn any(&self) -> bool {
+        self.positive || self.maybe || self.negative
+    }
+}
+
+#[derive(Debug)]
+struct CollectedSizednessBounds {
+    // Collected `Sized` bounds
+    sized: CollectedBound,
+    // Collected `MetaSized` bounds
+    meta_sized: CollectedBound,
+    // Collected `PointeeSized` bounds
+    pointee_sized: CollectedBound,
+}
+
+impl CollectedSizednessBounds {
+    /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered for `Sized`,
+    /// `MetaSized` or `PointeeSized`.
+    fn any(&self) -> bool {
+        self.sized.any() || self.meta_sized.any() || self.pointee_sized.any()
+    }
+}
+
+fn search_bounds_for<'tcx>(
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>),
+) {
+    let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+        for hir_bound in hir_bounds {
+            let hir::GenericBound::Trait(ptr) = hir_bound else {
+                continue;
+            };
+
+            f(ptr)
+        }
+    };
+
+    search_bounds(hir_bounds);
+    if let Some((self_ty, where_clause)) = self_ty_where_predicates {
+        for clause in where_clause {
+            if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind
+                && pred.is_param_bound(self_ty.to_def_id())
+            {
+                search_bounds(pred.bounds);
+            }
+        }
+    }
+}
+
+fn collect_unbounds<'tcx>(
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> {
+    let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
+    search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
+        if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) {
+            unbounds.push(ptr);
+        }
+    });
+    unbounds
+}
+
+fn collect_bounds<'a, 'tcx>(
+    hir_bounds: &'a [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    target_did: DefId,
+) -> CollectedBound {
+    let mut collect_into = CollectedBound::default();
+    search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
+        if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) {
+            return;
+        }
+
+        match ptr.modifiers.polarity {
+            hir::BoundPolarity::Maybe(_) => collect_into.maybe = true,
+            hir::BoundPolarity::Negative(_) => collect_into.negative = true,
+            hir::BoundPolarity::Positive => collect_into.positive = true,
+        }
+    });
+    collect_into
+}
+
+fn collect_sizedness_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    span: Span,
+) -> CollectedSizednessBounds {
+    let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+    let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did);
+
+    let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
+    let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did);
+
+    let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+    let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did);
+
+    CollectedSizednessBounds { sized, meta_sized, pointee_sized }
+}
+
+/// Add a trait bound for `did`.
+fn add_trait_bound<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+    self_ty: Ty<'tcx>,
+    did: DefId,
+    span: Span,
+) {
+    let trait_ref = ty::TraitRef::new(tcx, did, [self_ty]);
+    // Preferable to put sizedness obligations first, since we report better errors for `Sized`
+    // ambiguity.
+    bounds.insert(0, (trait_ref.upcast(tcx), span));
+}
+
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    pub(crate) fn add_default_traits(
+    /// Skip `PointeeSized` bounds.
+    ///
+    /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there
+    /// is actually the absence of any bounds. This avoids limitations around non-global where
+    /// clauses being preferred over item bounds (where `PointeeSized` bounds would be
+    /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is
+    /// added to some items.
+    pub(crate) fn should_skip_sizedness_bound<'hir>(
+        &self,
+        bound: &'hir hir::GenericBound<'tcx>,
+    ) -> bool {
+        bound
+            .trait_ref()
+            .and_then(|tr| tr.trait_def_id())
+            .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized))
+            .unwrap_or(false)
+    }
+
+    /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type.
+    ///
+    /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit
+    ///   sizedness bounds are present.
+    /// - On traits and trait aliases, add default `MetaSized` supertrait if no explicit sizedness
+    ///   bounds are present.
+    /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if
+    ///   a `?Sized` bound is present.
+    pub(crate) fn add_sizedness_bounds(
         &self,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
-        hir_bounds: &[hir::GenericBound<'tcx>],
+        hir_bounds: &'tcx [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+        trait_did: Option<LocalDefId>,
         span: Span,
     ) {
-        self.add_default_traits_with_filter(
-            bounds,
-            self_ty,
-            hir_bounds,
-            self_ty_where_predicates,
-            span,
-            |_| true,
-        );
+        let tcx = self.tcx();
+
+        let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
+        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+
+        // If adding sizedness bounds to a trait, then there are some relevant early exits
+        if let Some(trait_did) = trait_did {
+            let trait_did = trait_did.to_def_id();
+            // Never add a default supertrait to `PointeeSized`.
+            if trait_did == pointee_sized_did {
+                return;
+            }
+            // Don't add default sizedness supertraits to auto traits because it isn't possible to
+            // relax an automatically added supertrait on the defn itself.
+            if tcx.trait_is_auto(trait_did) {
+                return;
+            }
+        } else {
+            // Report invalid unbounds on sizedness-bounded generic parameters.
+            let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates);
+            self.check_and_report_invalid_unbounds_on_param(unbounds);
+        }
+
+        let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
+        if (collected.sized.maybe || collected.sized.negative)
+            && !collected.sized.positive
+            && !collected.meta_sized.any()
+            && !collected.pointee_sized.any()
+        {
+            // `?Sized` is equivalent to `MetaSized` (but only add the bound if there aren't any
+            // other explicit ones) - this can happen for trait aliases as well as bounds.
+            add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span);
+        } else if !collected.any() {
+            if trait_did.is_some() {
+                // If there are no explicit sizedness bounds on a trait then add a default
+                // `MetaSized` supertrait.
+                add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span);
+            } else {
+                // If there are no explicit sizedness bounds on a parameter then add a default
+                // `Sized` bound.
+                let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+                add_trait_bound(tcx, bounds, self_ty, sized_did, span);
+            }
+        }
     }
 
     /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
@@ -146,13 +336,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if !self.requires_default_supertraits(trait_bounds, trait_generics) {
             let self_ty_where_predicates = (parent, trait_item.generics.predicates);
-            self.add_default_traits_with_filter(
+            self.add_default_traits(
                 bounds,
                 tcx.types.self_param,
                 &[],
                 Some(self_ty_where_predicates),
                 trait_item.span,
-                |tr| tr != hir::LangItem::Sized,
             );
         }
     }
@@ -174,41 +363,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
         if self.requires_default_supertraits(hir_bounds, hir_generics) {
             let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
-            self.add_default_traits_with_filter(
+            self.add_default_traits(
                 bounds,
                 self.tcx().types.self_param,
                 hir_bounds,
                 Some(self_ty_where_predicates),
                 span,
-                |default_trait| default_trait != hir::LangItem::Sized,
             );
         }
     }
 
-    pub(crate) fn add_default_traits_with_filter(
+    pub(crate) fn add_default_traits(
         &self,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
         hir_bounds: &[hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
-        f: impl Fn(hir::LangItem) -> bool,
     ) {
-        self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each(
-            |default_trait| {
-                self.add_default_trait(
-                    *default_trait,
-                    bounds,
-                    self_ty,
-                    hir_bounds,
-                    self_ty_where_predicates,
-                    span,
-                );
-            },
-        );
+        self.tcx().default_traits().iter().for_each(|default_trait| {
+            self.add_default_trait(
+                *default_trait,
+                bounds,
+                self_ty,
+                hir_bounds,
+                self_ty_where_predicates,
+                span,
+            );
+        });
     }
 
-    /// Add a `Sized` or `experimental_default_bounds` bounds to the `bounds` if appropriate.
+    /// Add a `experimental_default_bounds` bound to the `bounds` if appropriate.
     ///
     /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`.
     pub(crate) fn add_default_trait(
@@ -220,7 +405,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
     ) {
-        let trait_id = self.tcx().lang_items().get(trait_);
+        let tcx = self.tcx();
+        let trait_id = tcx.lang_items().get(trait_);
         if let Some(trait_id) = trait_id
             && self.do_not_provide_default_trait_bound(
                 trait_id,
@@ -228,11 +414,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 self_ty_where_predicates,
             )
         {
-            // There was no `?Trait` or `!Trait` bound;
-            // add `Trait` if it's available.
-            let trait_ref = ty::TraitRef::new(self.tcx(), trait_id, [self_ty]);
-            // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-            bounds.insert(0, (trait_ref.upcast(self.tcx()), span));
+            add_trait_bound(tcx, bounds, self_ty, trait_id, span);
         }
     }
 
@@ -242,90 +424,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_bounds: &'a [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
     ) -> bool {
-        let tcx = self.tcx();
-        let mut seen_negative_bound = false;
-        let mut seen_positive_bound = false;
-
-        // Try to find an unbound in bounds.
-        let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
-        let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'tcx>]| {
-            for hir_bound in hir_bounds {
-                let hir::GenericBound::Trait(ptr) = hir_bound else {
-                    continue;
-                };
-                match ptr.modifiers.polarity {
-                    hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
-                    hir::BoundPolarity::Negative(_) => {
-                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
-                            seen_negative_bound = true;
-                        }
-                    }
-                    hir::BoundPolarity::Positive => {
-                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
-                            seen_positive_bound = true;
-                        }
-                    }
-                }
-            }
-        };
-        search_bounds(hir_bounds);
-        if let Some((self_ty, where_clause)) = self_ty_where_predicates {
-            for clause in where_clause {
-                if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind
-                    && pred.is_param_bound(self_ty.to_def_id())
-                {
-                    search_bounds(pred.bounds);
-                }
-            }
-        }
-
-        let mut unique_bounds = FxIndexSet::default();
-        let mut seen_repeat = false;
-        for unbound in &unbounds {
-            if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
-                seen_repeat |= !unique_bounds.insert(unbound_def_id);
-            }
-        }
-        if unbounds.len() > 1 {
-            let err = errors::MultipleRelaxedDefaultBounds {
-                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
-            };
-            if seen_repeat {
-                self.dcx().emit_err(err);
-            } else if !tcx.features().more_maybe_bounds() {
-                self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit();
-            };
-        }
-
-        let mut seen_unbound = false;
-        for unbound in unbounds {
-            let unbound_def_id = unbound.trait_ref.trait_def_id();
-            if unbound_def_id == Some(trait_def_id) {
-                seen_unbound = true;
-            }
-            let emit_relax_err = || {
-                let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
-                    true => "`?Sized` and `experimental_default_bounds`",
-                    false => "`?Sized`",
-                };
-                // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
-                self.dcx().span_err(
-                    unbound.span,
-                    format!(
-                        "relaxing a default bound only does something for {}; \
-                    all other traits are not bound by default",
-                        unbound_traits
-                    ),
-                );
-            };
-            match unbound_def_id {
-                Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_err(),
-                None => emit_relax_err(),
-                _ => {}
-            }
-        }
-
-        !(seen_unbound || seen_negative_bound || seen_positive_bound)
+        let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id);
+        !collected.any()
     }
 
     /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
@@ -361,6 +461,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         'tcx: 'hir,
     {
         for hir_bound in hir_bounds {
+            if self.should_skip_sizedness_bound(hir_bound) {
+                continue;
+            }
+
             // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`,
             // we skip over any traits that don't define the given associated type.
             if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index c7cdf1d5bd2..05465b47a26 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -61,14 +61,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let ast_bounds: Vec<_> =
             hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
 
-        self.add_default_traits_with_filter(
-            &mut user_written_bounds,
-            dummy_self,
-            &ast_bounds,
-            None,
-            span,
-            |tr| tr != hir::LangItem::Sized,
-        );
+        self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);
 
         let (elaborated_trait_bounds, elaborated_projection_bounds) =
             traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 45fee0fa402..1cda6dff21e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId};
+use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -34,6 +34,57 @@ use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
+    /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
+    pub(crate) fn check_and_report_invalid_unbounds_on_param(
+        &self,
+        unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
+    ) {
+        let tcx = self.tcx();
+
+        let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+
+        let mut unique_bounds = FxIndexSet::default();
+        let mut seen_repeat = false;
+        for unbound in &unbounds {
+            if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
+                seen_repeat |= !unique_bounds.insert(unbound_def_id);
+            }
+        }
+
+        if unbounds.len() > 1 {
+            let err = errors::MultipleRelaxedDefaultBounds {
+                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
+            };
+
+            if seen_repeat {
+                tcx.dcx().emit_err(err);
+            } else if !tcx.features().more_maybe_bounds() {
+                tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit();
+            };
+        }
+
+        for unbound in unbounds {
+            if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
+                && ((did == sized_did) || tcx.is_default_trait(did))
+            {
+                continue;
+            }
+
+            let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
+                true => "`?Sized` and `experimental_default_bounds`",
+                false => "`?Sized`",
+            };
+            self.dcx().span_err(
+                unbound.span,
+                format!(
+                    "relaxing a default bound only does something for {}; all other traits are \
+                     not bound by default",
+                    unbound_traits
+                ),
+            );
+        }
+    }
+
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
     pub(crate) fn report_missing_type_params(
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 850c9207877..f1395c242f2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1619,16 +1619,17 @@ impl<'tcx> TyCtxt<'tcx> {
         self.reserve_and_set_memory_dedup(alloc, salt)
     }
 
+    /// Traits added on all bounds by default, excluding `Sized` which is treated separately.
     pub fn default_traits(self) -> &'static [rustc_hir::LangItem] {
-        match self.sess.opts.unstable_opts.experimental_default_bounds {
-            true => &[
-                LangItem::Sized,
+        if self.sess.opts.unstable_opts.experimental_default_bounds {
+            &[
                 LangItem::DefaultTrait1,
                 LangItem::DefaultTrait2,
                 LangItem::DefaultTrait3,
                 LangItem::DefaultTrait4,
-            ],
-            false => &[LangItem::Sized],
+            ]
+        } else {
+            &[]
         }
     }
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 923c9242ff8..d996ee2b60a 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -95,7 +95,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
 /// `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 meta-sized type (str, slices, trait objects, etc)
 ///     - an pointee-sized type (extern types)
 ///     - a type parameter or projection whose sizedness can't be known
 ///