diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index c6472fd45fa98..370b15d2871a9 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -127,9 +127,6 @@ ast_lowering_misplaced_impl_trait =
     `impl Trait` is not allowed in {$position}
     .note = `impl Trait` is only allowed in arguments and return types of functions and methods
 
-ast_lowering_misplaced_relax_trait_bound =
-    `?Trait` bounds are only permitted at the point where a type parameter is declared
-
 ast_lowering_never_pattern_with_body =
     a never pattern is always unreachable
     .label = this will never be executed
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index b444324ef9143..83f3a976e83f7 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -324,13 +324,6 @@ pub(crate) struct MisplacedDoubleDot {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(ast_lowering_misplaced_relax_trait_bound)]
-pub(crate) struct MisplacedRelaxTraitBound {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(ast_lowering_match_arm_with_no_body)]
 pub(crate) struct MatchArmWithNoBody {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 8acb510577302..4df7697bcfb32 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -15,14 +15,11 @@ use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
-use super::errors::{
-    InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
-    UnionWithDefault,
-};
+use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
 use super::stability::{enabled_names, gate_unstable_abi};
 use super::{
     AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
-    ResolverAstLoweringExt,
+    RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
 };
 
 pub(super) struct ItemLowerer<'a, 'hir> {
@@ -427,6 +424,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     |this| {
                         let bounds = this.lower_param_bounds(
                             bounds,
+                            RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait),
                             ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         );
                         let items = this.arena.alloc_from_iter(
@@ -447,6 +445,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     |this| {
                         this.lower_param_bounds(
                             bounds,
+                            RelaxedBoundPolicy::Allowed,
                             ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         )
                     },
@@ -938,6 +937,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::TraitItemKind::Type(
                             this.lower_param_bounds(
                                 bounds,
+                                RelaxedBoundPolicy::Allowed,
                                 ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                             ),
                             ty,
@@ -1723,61 +1723,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         assert!(self.impl_trait_defs.is_empty());
         assert!(self.impl_trait_bounds.is_empty());
 
-        // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
-        // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
-        // these into hir when we lower thee where clauses), but this makes it quite difficult to
-        // keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
-        // checks both param bounds and where clauses for `?Sized`.
-        for pred in &generics.where_clause.predicates {
-            let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else {
-                continue;
-            };
-            let compute_is_param = || {
-                // Check if the where clause type is a plain type parameter.
-                match self
-                    .resolver
-                    .get_partial_res(bound_pred.bounded_ty.id)
-                    .and_then(|r| r.full_res())
-                {
-                    Some(Res::Def(DefKind::TyParam, def_id))
-                        if bound_pred.bound_generic_params.is_empty() =>
-                    {
-                        generics
-                            .params
-                            .iter()
-                            .any(|p| def_id == self.local_def_id(p.id).to_def_id())
-                    }
-                    // Either the `bounded_ty` is not a plain type parameter, or
-                    // it's not found in the generic type parameters list.
-                    _ => false,
-                }
-            };
-            // We only need to compute this once per `WherePredicate`, but don't
-            // need to compute this at all unless there is a Maybe bound.
-            let mut is_param: Option<bool> = None;
-            for bound in &bound_pred.bounds {
-                if !matches!(
-                    *bound,
-                    GenericBound::Trait(PolyTraitRef {
-                        modifiers: TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. },
-                        ..
-                    })
-                ) {
-                    continue;
-                }
-                let is_param = *is_param.get_or_insert_with(compute_is_param);
-                if !is_param && !self.tcx.features().more_maybe_bounds() {
-                    self.tcx
-                        .sess
-                        .create_feature_err(
-                            MisplacedRelaxTraitBound { span: bound.span() },
-                            sym::more_maybe_bounds,
-                        )
-                        .emit();
-                }
-            }
-        }
-
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
             self.lower_generic_bound_predicate(
@@ -1787,6 +1732,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 &param.bounds,
                 param.colon_span,
                 generics.span,
+                RelaxedBoundPolicy::Allowed,
                 itctx,
                 PredicateOrigin::GenericParam,
             )
@@ -1796,7 +1742,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 .where_clause
                 .predicates
                 .iter()
-                .map(|predicate| self.lower_where_predicate(predicate)),
+                .map(|predicate| self.lower_where_predicate(predicate, &generics.params)),
         );
 
         let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self
@@ -1873,6 +1819,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         bounds: &[GenericBound],
         colon_span: Option<Span>,
         parent_span: Span,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
@@ -1881,7 +1828,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             return None;
         }
 
-        let bounds = self.lower_param_bounds(bounds, itctx);
+        let bounds = self.lower_param_bounds(bounds, rbp, itctx);
 
         let param_span = ident.span;
 
@@ -1933,7 +1880,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
         Some(hir::WherePredicate { hir_id, span, kind })
     }
 
-    fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
+    fn lower_where_predicate(
+        &mut self,
+        pred: &WherePredicate,
+        params: &[ast::GenericParam],
+    ) -> hir::WherePredicate<'hir> {
         let hir_id = self.lower_node_id(pred.id);
         let span = self.lower_span(pred.span);
         self.lower_attrs(hir_id, &pred.attrs, span);
@@ -1942,17 +1893,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 bound_generic_params,
                 bounded_ty,
                 bounds,
-            }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
-                bound_generic_params: self
-                    .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
-                bounded_ty: self
-                    .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
-                bounds: self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                ),
-                origin: PredicateOrigin::WhereClause,
-            }),
+            }) => {
+                let rbp = if bound_generic_params.is_empty() {
+                    RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params)
+                } else {
+                    RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::LateBoundVarsInScope)
+                };
+                hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                    bound_generic_params: self.lower_generic_params(
+                        bound_generic_params,
+                        hir::GenericParamSource::Binder,
+                    ),
+                    bounded_ty: self.lower_ty(
+                        bounded_ty,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    ),
+                    bounds: self.lower_param_bounds(
+                        bounds,
+                        rbp,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    ),
+                    origin: PredicateOrigin::WhereClause,
+                })
+            }
             WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
                 hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
                     lifetime: self.lower_lifetime(
@@ -1962,6 +1925,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     ),
                     bounds: self.lower_param_bounds(
                         bounds,
+                        RelaxedBoundPolicy::Allowed,
                         ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                     ),
                     in_where_clause: true,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 26d7c0cd6d38f..8faf96a6df2d1 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -53,14 +53,14 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
 use rustc_hir::lints::DelayedLint;
 use rustc_hir::{
-    self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
-    LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
+    self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
+    LifetimeSyntax, ParamName, TraitCandidate,
 };
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
-use rustc_session::parse::add_feature_diagnostics;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, DesugaringKind, Span};
 use smallvec::SmallVec;
@@ -276,6 +276,20 @@ impl ResolverAstLowering {
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+enum RelaxedBoundPolicy<'a> {
+    Allowed,
+    AllowedIfOnTyParam(NodeId, &'a [ast::GenericParam]),
+    Forbidden(RelaxedBoundForbiddenReason),
+}
+
+#[derive(Clone, Copy, Debug)]
+enum RelaxedBoundForbiddenReason {
+    TraitObjectTy,
+    SuperTrait,
+    LateBoundVarsInScope,
+}
+
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -1079,10 +1093,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
                     hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
                 } else {
-                    // Desugar `AssocTy: Bounds` into an assoc type binding where the
-                    // later desugars into a trait predicate.
-                    let bounds = self.lower_param_bounds(bounds, itctx);
-
+                    // FIXME(#135229): These should be forbidden!
+                    let bounds =
+                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
                     hir::AssocItemConstraintKind::Bound { bounds }
                 }
             }
@@ -1210,6 +1223,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
                         span: t.span,
                     },
+                    RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitObjectTy),
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
@@ -1265,7 +1279,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     parenthesized: hir::GenericArgsParentheses::No,
                     span_ext: span,
                 });
-                let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args));
+                let path = self.make_lang_item_qpath(hir::LangItem::Pin, span, Some(args));
                 hir::TyKind::Path(path)
             }
             TyKind::BareFn(f) => {
@@ -1326,7 +1340,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             // takes care of rejecting invalid modifier combinations and
                             // const trait bounds in trait object types.
                             GenericBound::Trait(ty) => {
-                                let trait_ref = this.lower_poly_trait_ref(ty, itctx);
+                                let trait_ref = this.lower_poly_trait_ref(
+                                    ty,
+                                    RelaxedBoundPolicy::Forbidden(
+                                        RelaxedBoundForbiddenReason::TraitObjectTy,
+                                    ),
+                                    itctx,
+                                );
                                 Some(trait_ref)
                             }
                             GenericBound::Outlives(lifetime) => {
@@ -1381,9 +1401,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                         path
                     }
-                    ImplTraitContext::InBinding => {
-                        hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx))
-                    }
+                    ImplTraitContext::InBinding => hir::TyKind::TraitAscription(
+                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx),
+                    ),
                     ImplTraitContext::FeatureGated(position, feature) => {
                         let guar = self
                             .tcx
@@ -1499,7 +1519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
         self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| {
-            this.lower_param_bounds(bounds, itctx)
+            this.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx)
         })
     }
 
@@ -1793,10 +1813,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
-            GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)),
+            GenericBound::Trait(p) => {
+                hir::GenericBound::Trait(self.lower_poly_trait_ref(p, rbp, itctx))
+            }
             GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime(
                 lifetime,
                 LifetimeSource::OutlivesBound,
@@ -2011,19 +2034,81 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "debug", skip(self))]
     fn lower_poly_trait_ref(
         &mut self,
-        p: &PolyTraitRef,
+        tr: &PolyTraitRef,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
+        let PolyTraitRef { ref bound_generic_params, modifiers, ref trait_ref, span } = *tr;
+
         let bound_generic_params =
-            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
-        let trait_ref = self.lower_trait_ref(p.modifiers, &p.trait_ref, itctx);
-        let modifiers = self.lower_trait_bound_modifiers(p.modifiers);
+            self.lower_lifetime_binder(trait_ref.ref_id, bound_generic_params);
+        let trait_ref = self.lower_trait_ref(modifiers, trait_ref, itctx);
+        let modifiers = self.lower_trait_bound_modifiers(modifiers);
+
+        if let ast::BoundPolarity::Maybe(_) = modifiers.polarity {
+            self.validate_relaxed_bound(trait_ref, span, rbp);
+        }
+
         hir::PolyTraitRef {
             bound_generic_params,
             modifiers,
             trait_ref,
-            span: self.lower_span(p.span),
+            span: self.lower_span(span),
+        }
+    }
+
+    fn validate_relaxed_bound(
+        &self,
+        trait_ref: hir::TraitRef<'_>,
+        span: Span,
+        rbp: RelaxedBoundPolicy<'_>,
+    ) {
+        let err = |message| feature_err(&self.tcx.sess, sym::more_maybe_bounds, span, message);
+
+        match rbp {
+            RelaxedBoundPolicy::Allowed => return,
+            RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => {
+                if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res())
+                    && let Res::Def(DefKind::TyParam, def_id) = res
+                    && params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id())
+                {
+                    return;
+                }
+                if self.tcx.features().more_maybe_bounds() {
+                    return;
+                }
+            }
+            RelaxedBoundPolicy::Forbidden(reason) => {
+                if self.tcx.features().more_maybe_bounds() {
+                    return;
+                }
+
+                match reason {
+                    RelaxedBoundForbiddenReason::TraitObjectTy => {
+                        err("relaxed bounds are not permitted in trait object types").emit();
+                        return;
+                    }
+                    RelaxedBoundForbiddenReason::SuperTrait => {
+                        let mut diag = err("relaxed bounds are not permitted in supertrait bounds");
+                        if let Some(def_id) = trait_ref.trait_def_id()
+                            && self.tcx.is_lang_item(def_id, hir::LangItem::Sized)
+                        {
+                            diag.note("traits are `?Sized` by default");
+                        }
+                        diag.emit();
+                        return;
+                    }
+                    RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
+                };
+            }
         }
+
+        err("this relaxed bound is not permitted here")
+            .with_note(
+                "in this context, relaxed bounds are only allowed on \
+                 type parameters defined by the closest item",
+            )
+            .emit();
     }
 
     fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
@@ -2034,17 +2119,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
-        self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
+        self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, rbp, itctx))
     }
 
     fn lower_param_bounds_mut(
         &mut self,
         bounds: &[GenericBound],
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> impl Iterator<Item = hir::GenericBound<'hir>> {
-        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
+        bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx))
     }
 
     #[instrument(level = "debug", skip(self), ret)]
@@ -2078,6 +2165,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             bounds,
             /* colon_span */ None,
             span,
+            RelaxedBoundPolicy::Allowed,
             ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 4290f7b7edeb0..fb5a41f352853 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -212,11 +212,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
 ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
     .help = use `auto trait Trait {"{}"}` instead
 
-ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
-
-ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
-    .note = traits are `?{$path_str}` by default
-
 ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
     .suggestion = reorder the parameters: lifetimes, then consts and types
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index da24825120376..62182fdb26fca 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1373,29 +1373,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         match bound {
             GenericBound::Trait(trait_ref) => {
                 match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
-                    (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds() =>
-                    {
-                        self.sess
-                            .create_feature_err(
-                                errors::OptionalTraitSupertrait {
-                                    span: trait_ref.span,
-                                    path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
-                                },
-                                sym::more_maybe_bounds,
-                            )
-                            .emit();
-                    }
-                    (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds() =>
-                    {
-                        self.sess
-                            .create_feature_err(
-                                errors::OptionalTraitObject { span: trait_ref.span },
-                                sym::more_maybe_bounds,
-                            )
-                            .emit();
-                    }
                     (
                         BoundKind::TraitObject,
                         BoundConstness::Always(_),
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index d387a4a310ea0..2e0fac8ec0b30 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -566,22 +566,6 @@ pub(crate) struct NestedLifetimes {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(ast_passes_optional_trait_supertrait)]
-#[note]
-pub(crate) struct OptionalTraitSupertrait {
-    #[primary_span]
-    pub span: Span,
-    pub path_str: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(ast_passes_optional_trait_object)]
-pub(crate) struct OptionalTraitObject {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(ast_passes_const_bound_trait_object)]
 pub(crate) struct ConstBoundTraitObject {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0203.md b/compiler/rustc_error_codes/src/error_codes/E0203.md
index 1edb519275f79..a4dceedbf1fd1 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0203.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0203.md
@@ -1,15 +1,15 @@
-Having multiple relaxed default bounds is unsupported.
+Having duplicate relaxed default bounds is unsupported.
 
 Erroneous code example:
 
 ```compile_fail,E0203
-struct Bad<T: ?Sized + ?Send>{
-    inner: T
+struct Bad<T: ?Sized + ?Sized>{
+    inner: T,
 }
 ```
 
-Here the type `T` cannot have a relaxed bound for multiple default traits
-(`Sized` and `Send`). This can be fixed by only using one relaxed bound.
+Here the type parameter `T` cannot have duplicate relaxed bounds for default
+trait `Sized`. This can be fixed by only using one relaxed bound:
 
 ```
 struct Good<T: ?Sized>{
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 529d3578985ae..a2fd665f2a4fa 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -371,9 +371,6 @@ hir_analysis_missing_type_params =
         *[other] parameters
     } must be specified on the object type
 
-hir_analysis_multiple_relaxed_default_bounds =
-    type parameter has more than one relaxed default bound, only one is supported
-
 hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
 
 hir_analysis_must_implement_not_function = not a function
@@ -448,8 +445,6 @@ hir_analysis_parenthesized_fn_trait_expansion =
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
 
-hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects
-
 hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
     .label = `Self` is not a generic argument, but an alias to the type of the {$what}
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index a93e58b101fe5..70b6482273f59 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -266,20 +266,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         match predicate.kind {
             hir::WherePredicateKind::BoundPredicate(bound_pred) => {
                 let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
-
                 let bound_vars = tcx.late_bound_vars(predicate.hir_id);
-                // Keep the type around in a dummy predicate, in case of no bounds.
-                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
-                // is still checked for WF.
+
+                // This is a `where Ty:` (sic!).
                 if bound_pred.bounds.is_empty() {
                     if let ty::Param(_) = ty.kind() {
-                        // This is a `where T:`, which can be in the HIR from the
-                        // transformation that moves `?Sized` to `T`'s declaration.
-                        // We can skip the predicate because type parameters are
-                        // trivially WF, but also we *should*, to avoid exposing
-                        // users who never wrote `where Type:,` themselves, to
-                        // compiler/tooling bugs from not handling WF predicates.
+                        // We can skip the predicate because type parameters are trivially WF.
                     } else {
+                        // Keep the type around in a dummy predicate. That way, it's not a complete
+                        // noop (see #53696) and `Ty` is still checked for WF.
+
                         let span = bound_pred.bounded_ty.span;
                         let predicate = ty::Binder::bind_with_vars(
                             ty::ClauseKind::WellFormed(ty.into()),
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c1c828392126f..9f2371b41b69b 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -278,13 +278,6 @@ pub(crate) struct CopyImplOnTypeWithDtor {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)]
-pub(crate) struct MultipleRelaxedDefaultBounds {
-    #[primary_span]
-    pub spans: Vec<Span>,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)]
 pub(crate) struct CopyImplOnNonAdt {
@@ -318,13 +311,6 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits {
     pub trait_alias_span: Option<Span>,
 }
 
-#[derive(Diagnostic)]
-#[diag(hir_analysis_pointee_sized_trait_object)]
-pub(crate) struct PointeeSizedTraitObject {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)]
 pub(crate) struct AmbiguousLifetimeBound {
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 d17986d45d2f2..161fbba9cde57 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
-use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
+use rustc_hir::{AmbigArg, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -85,17 +85,17 @@ fn search_bounds_for<'tcx>(
     }
 }
 
-fn collect_unbounds<'tcx>(
+fn collect_relaxed_bounds<'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();
+    let mut relaxed_bounds: 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);
+            relaxed_bounds.push(ptr);
         }
     });
-    unbounds
+    relaxed_bounds
 }
 
 fn collect_bounds<'a, 'tcx>(
@@ -124,13 +124,13 @@ fn collect_sizedness_bounds<'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_did = tcx.require_lang_item(hir::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_did = tcx.require_lang_item(hir::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_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
     let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did);
 
     CollectedSizednessBounds { sized, meta_sized, pointee_sized }
@@ -151,24 +151,6 @@ fn add_trait_bound<'tcx>(
 }
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    /// 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
@@ -193,8 +175,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return;
         }
 
-        let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
-        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+        let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span);
+        let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
 
         // If adding sizedness bounds to a trait, then there are some relevant early exits
         if let Some(trait_did) = trait_did {
@@ -209,9 +191,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 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);
+            // Report invalid relaxed bounds.
+            // FIXME: Since we only call this validation function here in this function, we only
+            //        fully validate relaxed bounds in contexts where we perform
+            //        "sized elaboration". In most cases that doesn't matter because we *usually*
+            //        reject relaxed bounds outright during AST lowering.
+            //        However, this can easily get out of sync! Ideally, we would perform this step
+            //        where we are guaranteed to catch *all* bounds like in
+            //        `Self::lower_poly_trait_ref`. List of concrete issues:
+            //        FIXME(more_maybe_bounds): We don't call this for e.g., trait object tys or
+            //                                  supertrait bounds!
+            //        FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
+            //                                       AST lowering should reject them outright.
+            //        FIXME(associated_type_bounds): We don't call this for them. However, AST
+            //                                       lowering should reject them outright (#135229).
+            let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
+            self.check_and_report_invalid_relaxed_bounds(bounds);
         }
 
         let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
@@ -231,7 +226,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             } 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);
+                let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span);
                 add_trait_bound(tcx, bounds, self_ty, sized_did, span);
             }
         }
@@ -463,10 +458,6 @@ 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 {
@@ -482,12 +473,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref) => {
-                    let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
                     let _ = self.lower_poly_trait_ref(
-                        &poly_trait_ref.trait_ref,
-                        poly_trait_ref.span,
-                        constness,
-                        polarity,
+                        poly_trait_ref,
                         param_ty,
                         bounds,
                         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 cb106962be18e..76bb59e3f0901 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
@@ -2,7 +2,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
-use rustc_hir::LangItem;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
@@ -18,9 +17,7 @@ use tracing::{debug, instrument};
 
 use super::HirTyLowerer;
 use crate::errors::SelfInTypeAlias;
-use crate::hir_ty_lowering::{
-    GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
-};
+use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Lower a trait object type from the HIR to our internal notion of a type.
@@ -38,24 +35,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         let mut user_written_bounds = Vec::new();
         let mut potential_assoc_types = Vec::new();
-        for trait_bound in hir_bounds.iter() {
-            if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
-                continue;
-            }
-            if let GenericArgCountResult {
-                correct:
-                    Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
-                ..
-            } = self.lower_poly_trait_ref(
-                &trait_bound.trait_ref,
-                trait_bound.span,
-                hir::BoundConstness::Never,
-                hir::BoundPolarity::Positive,
+        for poly_trait_ref in hir_bounds.iter() {
+            let result = self.lower_poly_trait_ref(
+                poly_trait_ref,
                 dummy_self,
                 &mut user_written_bounds,
                 PredicateFilter::SelfOnly,
-            ) {
-                potential_assoc_types.extend(cur_potential_assoc_types);
+            );
+            if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
+                potential_assoc_types.extend(invalid_args);
             }
         }
 
@@ -81,13 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let guar = self.report_trait_object_addition_traits(&regular_traits);
             return Ty::new_error(tcx, guar);
         }
-        // We don't support `PointeeSized` principals
-        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
-        if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) {
-            let guar = self.report_pointee_sized_trait_object(span);
-            return Ty::new_error(tcx, guar);
-        }
-
         // Don't create a dyn trait if we have errors in the principal.
         if let Err(guar) = regular_traits.error_reported() {
             return Ty::new_error(tcx, guar);
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 5d85a3f8455e0..287a5532f0168 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, LangItem, PolyTraitRef};
+use rustc_hir::{self as hir, HirId, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -29,59 +29,54 @@ use tracing::debug;
 use super::InherentAssocCandidate;
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 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(
+    /// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
+    pub(crate) fn check_and_report_invalid_relaxed_bounds(
         &self,
-        unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
+        relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
     ) {
         let tcx = self.tcx();
 
-        let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+        let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
 
-        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);
+        for bound in &relaxed_bounds {
+            if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
+                grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
             }
         }
 
-        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 (trait_def_id, spans) in grouped_bounds {
+            if spans.len() > 1 {
+                let name = tcx.item_name(trait_def_id);
+                self.dcx()
+                    .struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
+                    .with_code(E0203)
+                    .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))
+        let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
+
+        for bound in relaxed_bounds {
+            if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
+                && (def_id == sized_def_id || tcx.is_default_trait(def_id))
             {
                 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
-                ),
+                bound.span,
+                if tcx.sess.opts.unstable_opts.experimental_default_bounds
+                    || tcx.features().more_maybe_bounds()
+                {
+                    "bound modifier `?` can only be applied to default traits like `Sized`"
+                } else {
+                    "bound modifier `?` can only be applied to `Sized`"
+                },
             );
         }
     }
@@ -1410,10 +1405,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
-
-    pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed {
-        self.dcx().emit_err(PointeeSizedTraitObject { span })
-    }
 }
 
 /// Emit an error for the given associated item constraint.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 55bf2ab6b50e1..51f4007b09ba6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -750,18 +750,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
     /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`.
     /// The lowered poly-trait-ref will track this binder explicitly, however.
-    #[instrument(level = "debug", skip(self, span, constness, bounds))]
+    #[instrument(level = "debug", skip(self, bounds))]
     pub(crate) fn lower_poly_trait_ref(
         &self,
-        trait_ref: &hir::TraitRef<'tcx>,
-        span: Span,
-        constness: hir::BoundConstness,
-        polarity: hir::BoundPolarity,
+        poly_trait_ref: &hir::PolyTraitRef<'tcx>,
         self_ty: Ty<'tcx>,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         predicate_filter: PredicateFilter,
     ) -> GenericArgCountResult {
+        let tcx = self.tcx();
+
+        // We use the *resolved* bound vars later instead of the HIR ones since the former
+        // also include the bound vars of the overarching predicate if applicable.
+        let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
+            *poly_trait_ref;
+        let hir::TraitBoundModifiers { constness, polarity } = modifiers;
+
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
+
+        let (polarity, bounds) = match polarity {
+            rustc_ast::BoundPolarity::Positive
+                if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) =>
+            {
+                // 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.
+                (ty::PredicatePolarity::Positive, &mut Vec::new())
+            }
+            rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
+            rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
+            rustc_ast::BoundPolarity::Maybe(_) => {
+                (ty::PredicatePolarity::Positive, &mut Vec::new())
+            }
+        };
+
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
         let _ = self.prohibit_generic_args(
@@ -778,7 +804,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(self_ty),
         );
 
-        let tcx = self.tcx();
         let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
         debug!(?bound_vars);
 
@@ -789,27 +814,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         debug!(?poly_trait_ref);
 
-        let polarity = match polarity {
-            rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
-            rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
-            rustc_ast::BoundPolarity::Maybe(_) => {
-                // Validate associated type at least. We may want to reject these
-                // outright in the future...
-                for constraint in trait_segment.args().constraints {
-                    let _ = self.lower_assoc_item_constraint(
-                        trait_ref.hir_ref_id,
-                        poly_trait_ref,
-                        constraint,
-                        &mut Default::default(),
-                        &mut Default::default(),
-                        constraint.span,
-                        predicate_filter,
-                    );
-                }
-                return arg_count;
-            }
-        };
-
         // We deal with const conditions later.
         match predicate_filter {
             PredicateFilter::All
@@ -912,7 +916,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // Don't register any associated item constraints for negative bounds,
             // since we should have emitted an error for them earlier, and they
             // would not be well-formed!
-            if polarity != ty::PredicatePolarity::Positive {
+            if polarity == ty::PredicatePolarity::Negative {
                 self.dcx().span_delayed_bug(
                     constraint.span,
                     "negative trait bounds should not have assoc item constraints",
diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
index b90bb9ea4ddf6..029ce7d0e7e49 100644
--- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
+++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
@@ -1,8 +1,7 @@
 // Regression test for <https://github.com/rust-lang/rust/issues/137554>.
 
 fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-    //~^ ERROR `?Trait` is not permitted in trait object types
-    //~| ERROR expected trait, found associated function `Iterator::advance_by`
-    //~| ERROR the value of the associated type `Item` in `Iterator` must be specified
+    //~^ ERROR expected trait, found associated function `Iterator::advance_by`
+    //~| ERROR relaxed bounds are not permitted in trait object types
     todo!()
 }
diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
index 7f0fbc800ed1c..3dc7fd78e41e8 100644
--- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
+++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
@@ -1,25 +1,19 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29
-   |
-LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0404]: expected trait, found associated function `Iterator::advance_by`
   --> $DIR/missing-associated_item_or_field_def_ids.rs:3:30
    |
 LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait
 
-error[E0191]: the value of the associated type `Item` in `Iterator` must be specified
-  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:18
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29
    |
 LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-   |                  ^^^^^^^^ help: specify the associated type: `Iterator<Item = Type>`
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0191, E0404, E0658.
-For more information about an error, try `rustc --explain E0191`.
+Some errors have detailed explanations: E0404, E0658.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
index f6b749a5100b9..bac4e60886772 100644
--- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
+++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
@@ -6,7 +6,6 @@ trait Tr {
 
 fn main() {
     let _: dyn Tr + ?Foo<Assoc = ()>;
-    //~^ ERROR: `?Trait` is not permitted in trait object types
-    //~| ERROR: cannot find trait `Foo` in this scope
-    //~| ERROR: the value of the associated type `Item` in `Tr` must be specified
+    //~^ ERROR: cannot find trait `Foo` in this scope
+    //~| ERROR: relaxed bounds are not permitted in trait object types
 }
diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
index f31a1de76a790..3b35c164d37d4 100644
--- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
+++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
@@ -1,28 +1,19 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21
-   |
-LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
-   |                     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0405]: cannot find trait `Foo` in this scope
   --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:22
    |
 LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
    |                      ^^^ not found in this scope
 
-error[E0191]: the value of the associated type `Item` in `Tr` must be specified
-  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:16
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21
    |
-LL |     type Item;
-   |     --------- `Item` defined here
-...
 LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
-   |                ^^ help: specify the associated type: `Tr<Item = Type>`
+   |                     ^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0191, E0405, E0658.
-For more information about an error, try `rustc --explain E0191`.
+Some errors have detailed explanations: E0405, E0658.
+For more information about an error, try `rustc --explain E0405`.
diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
index 6a832744e3ee9..9c727ae3aad4c 100644
--- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
+++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
@@ -2,23 +2,13 @@
 
 trait Trait1 {}
 auto trait Trait2 {}
-trait Trait3: ?Trait1 {}
-//~^  ERROR `?Trait` is not permitted in supertraits
-trait Trait4 where Self: ?Trait1 {}
-//~^ ERROR ?Trait` bounds are only permitted at the point where a type parameter is declared
+trait Trait3: ?Trait1 {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
+trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitted here
 
 fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
-//~^  ERROR `?Trait` is not permitted in trait object types
+//~^  ERROR relaxed bounds are not permitted in trait object types
 fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-trait Trait {}
-// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions
-fn baz<T: ?Trait + ?Trait>(_ : T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
index 729df4eb37cac..d01d9cbef3adc 100644
--- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
+++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
@@ -1,71 +1,43 @@
-error[E0658]: `?Trait` is not permitted in supertraits
+error[E0658]: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/feature-gate-more-maybe-bounds.rs:5:15
    |
 LL | trait Trait3: ?Trait1 {}
    |               ^^^^^^^
    |
-   = note: traits are `?Trait1` by default
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/feature-gate-more-maybe-bounds.rs:10:28
-   |
-LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
-   |                            ^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/feature-gate-more-maybe-bounds.rs:7:26
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/feature-gate-more-maybe-bounds.rs:6:26
    |
 LL | trait Trait4 where Self: ?Trait1 {}
    |                          ^^^^^^^
    |
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:11
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/feature-gate-more-maybe-bounds.rs:8:28
    |
-LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
-   |           ^^^^^^^   ^^^^^^^
+LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
+   |                            ^^^^^^^
    |
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:11
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/feature-gate-more-maybe-bounds.rs:10:11
    |
 LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
    |           ^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:21
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/feature-gate-more-maybe-bounds.rs:10:21
    |
 LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
    |                     ^^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:11
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |           ^^^^^^   ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:11
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |           ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:20
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |                    ^^^^^^
-
-error: aborting due to 9 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0203, E0658.
-For more information about an error, try `rustc --explain E0203`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
index 27c493a13bf91..7e0e1eadf9c75 100644
--- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
+++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
@@ -3,8 +3,8 @@
 
 use std::future::Future;
 fn foo() -> impl ?Future<Output = impl Send> {
-    //~^ ERROR: relaxing a default bound only does something for `?Sized`
-    //~| ERROR: relaxing a default bound only does something for `?Sized`
+    //~^ ERROR: bound modifier `?` can only be applied to `Sized`
+    //~| ERROR: bound modifier `?` can only be applied to `Sized`
     ()
 }
 
diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
index dc4314c58ad2f..f99d6a7e5f6d0 100644
--- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
+++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/opt-out-bound-not-satisfied.rs:5:18
    |
 LL | fn foo() -> impl ?Future<Output = impl Send> {
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/opt-out-bound-not-satisfied.rs:5:18
    |
 LL | fn foo() -> impl ?Future<Output = impl Send> {
diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs
index 09d60b7786b99..63f6479ae2e24 100644
--- a/tests/ui/issues/issue-37534.rs
+++ b/tests/ui/issues/issue-37534.rs
@@ -1,5 +1,5 @@
 struct Foo<T: ?Hash> {}
 //~^ ERROR expected trait, found derive macro `Hash`
-//~| ERROR relaxing a default bound only does something for `?Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr
index 3219854bc70ce..0860735420301 100644
--- a/tests/ui/issues/issue-37534.stderr
+++ b/tests/ui/issues/issue-37534.stderr
@@ -9,7 +9,7 @@ help: consider importing this trait instead
 LL + use std::hash::Hash;
    |
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-37534.rs:1:15
    |
 LL | struct Foo<T: ?Hash> {}
diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs
index 4e4e35c6a71e8..dd9dfc74ca352 100644
--- a/tests/ui/issues/issue-87199.rs
+++ b/tests/ui/issues/issue-87199.rs
@@ -6,12 +6,12 @@
 
 // Check that these function definitions only emit warnings, not errors
 fn arg<T: ?Send>(_: T) {}
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
 fn ref_arg<T: ?Send>(_: &T) {}
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
 fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
-//~| ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
+//~| ERROR: bound modifier `?` can only be applied to `Sized`
 
 // Check that there's no `?Sized` relaxation!
 fn main() {
diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr
index acc4e84779c9c..8a930a3d704c1 100644
--- a/tests/ui/issues/issue-87199.stderr
+++ b/tests/ui/issues/issue-87199.stderr
@@ -1,22 +1,22 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:8:11
    |
 LL | fn arg<T: ?Send>(_: T) {}
    |           ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:10:15
    |
 LL | fn ref_arg<T: ?Send>(_: &T) {}
    |               ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:12:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    |                                        ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:12:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
diff --git a/tests/ui/parser/trait-object-trait-parens.rs b/tests/ui/parser/trait-object-trait-parens.rs
index 438034bc38aa4..51f0e2de6116f 100644
--- a/tests/ui/parser/trait-object-trait-parens.rs
+++ b/tests/ui/parser/trait-object-trait-parens.rs
@@ -6,17 +6,17 @@ fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
 
 fn main() {
     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr
index d75352b6811ea..8f8ddeac1c5aa 100644
--- a/tests/ui/parser/trait-object-trait-parens.stderr
+++ b/tests/ui/parser/trait-object-trait-parens.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `?Trait` is not permitted in trait object types
+error[E0658]: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:8:24
    |
 LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
@@ -7,7 +7,7 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in trait object types
+error[E0658]: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:13:16
    |
 LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
@@ -16,7 +16,7 @@ LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in trait object types
+error[E0658]: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:18:44
    |
 LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
diff --git a/tests/ui/sized-hierarchy/default-bound.rs b/tests/ui/sized-hierarchy/default-bound.rs
index 12b2eb2b5c1b4..bbb2c6d96baa8 100644
--- a/tests/ui/sized-hierarchy/default-bound.rs
+++ b/tests/ui/sized-hierarchy/default-bound.rs
@@ -14,13 +14,13 @@ fn neg_sized<T: ?Sized>() {}
 fn metasized<T: MetaSized>() {}
 
 fn neg_metasized<T: ?MetaSized>() {}
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 
 fn pointeesized<T: PointeeSized>() { }
 
 fn neg_pointeesized<T: ?PointeeSized>() { }
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 
 fn main() {
diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr
index 22f0fa29d3e23..0a4ea6f44d8ed 100644
--- a/tests/ui/sized-hierarchy/default-bound.stderr
+++ b/tests/ui/sized-hierarchy/default-bound.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/default-bound.rs:16:21
    |
 LL | fn neg_metasized<T: ?MetaSized>() {}
    |                     ^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/default-bound.rs:22:24
    |
 LL | fn neg_pointeesized<T: ?PointeeSized>() { }
diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs
index b25acf9e6ea4f..ab3b28e84db5a 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.rs
+++ b/tests/ui/sized-hierarchy/default-supertrait.rs
@@ -6,18 +6,18 @@ use std::marker::{MetaSized, PointeeSized};
 trait Sized_: Sized { }
 
 trait NegSized: ?Sized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 trait MetaSized_: MetaSized { }
 
 trait NegMetaSized: ?MetaSized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 
 trait PointeeSized_: PointeeSized { }
 
 trait NegPointeeSized: ?PointeeSized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 trait Bare {}
 
diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr
index de23936b900bc..77cb9755d4a1c 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.stderr
+++ b/tests/ui/sized-hierarchy/default-supertrait.stderr
@@ -1,30 +1,28 @@
-error[E0658]: `?Trait` is not permitted in supertraits
+error[E0658]: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:8:17
    |
 LL | trait NegSized: ?Sized { }
    |                 ^^^^^^
    |
-   = note: traits are `?Sized` by default
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: traits are `?Sized` by default
 
-error[E0658]: `?Trait` is not permitted in supertraits
+error[E0658]: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:13:21
    |
 LL | trait NegMetaSized: ?MetaSized { }
    |                     ^^^^^^^^^^
    |
-   = note: traits are `?MetaSized` by default
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in supertraits
+error[E0658]: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:19:24
    |
 LL | trait NegPointeeSized: ?PointeeSized { }
    |                        ^^^^^^^^^^^^^
    |
-   = note: traits are `?PointeeSized` by default
    = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
diff --git a/tests/ui/sized-hierarchy/pointee-validation.rs b/tests/ui/sized-hierarchy/pointee-validation.rs
new file mode 100644
index 0000000000000..c80b26b310ae5
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pointee-validation.rs
@@ -0,0 +1,20 @@
+// Test that despite us dropping `PointeeSized` bounds during HIR ty lowering
+// we still validate it first.
+// issue: <https://github.com/rust-lang/rust/issues/142718>
+#![feature(sized_hierarchy)]
+
+use std::marker::PointeeSized;
+
+struct T where (): PointeeSized<(), Undefined = ()>;
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+//~| ERROR associated type `Undefined` not found for `PointeeSized`
+
+const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+//~^ ERROR `const` can only be applied to `#[const_trait]` traits
+//~| ERROR `const` can only be applied to `#[const_trait]` traits
+//~| ERROR const trait impls are experimental
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR const trait impls are experimental
+
+fn main() {}
diff --git a/tests/ui/sized-hierarchy/pointee-validation.stderr b/tests/ui/sized-hierarchy/pointee-validation.stderr
new file mode 100644
index 0000000000000..36500290e6c4d
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pointee-validation.stderr
@@ -0,0 +1,76 @@
+error[E0658]: const trait impls are experimental
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/pointee-validation.rs:8:20
+   |
+LL | struct T where (): PointeeSized<(), Undefined = ()>;
+   |                    ^^^^^^^^^^^^-------------------- help: remove the unnecessary generics
+   |                    |
+   |                    expected 0 generic arguments
+
+error[E0220]: associated type `Undefined` not found for `PointeeSized`
+  --> $DIR/pointee-validation.rs:8:37
+   |
+LL | struct T where (): PointeeSized<(), Undefined = ()>;
+   |                                     ^^^^^^^^^ associated type `Undefined` not found
+
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0107, E0220, E0658.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
index ece1702679d00..89e4c15371d4a 100644
--- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
@@ -3,7 +3,7 @@
 use std::marker::PointeeSized;
 
 type Foo = dyn PointeeSized;
-//~^ ERROR `PointeeSized` cannot be used with trait objects
+//~^ ERROR at least one trait is required for an object type
 
 fn foo(f: &Foo) {}
 
@@ -12,5 +12,5 @@ fn main() {
 
     let x = main;
     let y: Box<dyn PointeeSized> = x;
-//~^ ERROR `PointeeSized` cannot be used with trait objects
+//~^ ERROR at least one trait is required for an object type
 }
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
index a833c6952fdc5..616b2400f8650 100644
--- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
@@ -1,10 +1,10 @@
-error: `PointeeSized` cannot be used with trait objects
+error[E0224]: at least one trait is required for an object type
   --> $DIR/reject-dyn-pointeesized.rs:5:12
    |
 LL | type Foo = dyn PointeeSized;
    |            ^^^^^^^^^^^^^^^^
 
-error: `PointeeSized` cannot be used with trait objects
+error[E0224]: at least one trait is required for an object type
   --> $DIR/reject-dyn-pointeesized.rs:14:16
    |
 LL |     let y: Box<dyn PointeeSized> = x;
@@ -12,3 +12,4 @@ LL |     let y: Box<dyn PointeeSized> = x;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs
new file mode 100644
index 0000000000000..a1681ddec77b0
--- /dev/null
+++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs
@@ -0,0 +1,22 @@
+fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+//~^ ERROR duplicate relaxed `Sized` bounds
+//~| ERROR duplicate relaxed `Iterator` bounds
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+
+trait Trait {
+    // We used to say "type parameter has more than one relaxed default bound"
+    // even on *associated types* like here. Test that we no longer do that.
+    type Type: ?Sized + ?Sized;
+    //~^ ERROR duplicate relaxed `Sized` bounds
+    //~| ERROR duplicate relaxed `Sized` bounds
+}
+
+// We used to emit an additional error about "multiple relaxed default bounds".
+// However, multiple relaxed bounds are actually *fine* if they're distinct.
+// Ultimately, we still reject this because `Sized` is
+// the only (stable) default trait, so we're fine.
+fn not_dupes<T: ?Sized + ?Iterator>() {}
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr
new file mode 100644
index 0000000000000..ccc723fc7a653
--- /dev/null
+++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr
@@ -0,0 +1,47 @@
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:1:13
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |             ^^^^^^   ^^^^^^
+
+error[E0203]: duplicate relaxed `Iterator` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:1:31
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                               ^^^^^^^^^   ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:1:31
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                               ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:1:43
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                                           ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:19:26
+   |
+LL | fn not_dupes<T: ?Sized + ?Iterator>() {}
+   |                          ^^^^^^^^^
+
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:10:16
+   |
+LL |     type Type: ?Sized + ?Sized;
+   |                ^^^^^^   ^^^^^^
+
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:10:16
+   |
+LL |     type Type: ?Sized + ?Sized;
+   |                ^^^^^^   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0203`.
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs
similarity index 51%
rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs
index e6d7f74880fb2..1aa36207bc3ea 100644
--- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
+++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs
@@ -1,39 +1,38 @@
-// Regression test for #127441
-
-// Tests that we make the correct suggestion
-// in case there are more than one `?Sized`
-// bounds on a function parameter
+// Test that we emit a correct structured suggestions for dynamically sized ("maybe unsized")
+// function parameters.
+// We used to emit a butchered suggestion if duplicate relaxed `Sized` bounds were present.
+// issue: <https://github.com/rust-lang/rust/issues/127441>.
 
 use std::fmt::Debug;
 
 fn foo1<T: ?Sized>(a: T) {}
-//~^ ERROR he size for values of type `T` cannot be known at compilation time
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo2<T: ?Sized + ?Sized>(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR he size for values of type `T` cannot be known at compilation time
+//~^ ERROR duplicate relaxed `Sized` bounds
+//~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo5(_: impl ?Sized) {}
 //~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
 
 fn foo6(_: impl ?Sized + ?Sized) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
 
 fn foo7(_: impl ?Sized + ?Sized + Debug) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
 
 fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr
similarity index 80%
rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr
index 363f52d6df8d5..7a9c2f043ac41 100644
--- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
+++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr
@@ -1,41 +1,41 @@
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:12
    |
 LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
    |            ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:12
    |
 LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
    |            ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:12
    |
 LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
    |            ^^^^^^           ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:17
    |
 LL | fn foo6(_: impl ?Sized + ?Sized) {}
    |                 ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:17
    |
 LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
    |                 ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:17
    |
 LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
    |                 ^^^^^^           ^^^^^^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:8:23
    |
 LL | fn foo1<T: ?Sized>(a: T) {}
    |         -             ^ doesn't have a size known at compile-time
@@ -54,7 +54,7 @@ LL | fn foo1<T: ?Sized>(a: &T) {}
    |                       +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:32
    |
 LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
    |         -                      ^ doesn't have a size known at compile-time
@@ -73,7 +73,7 @@ LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
    |                                +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:40
    |
 LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
    |         -                              ^ doesn't have a size known at compile-time
@@ -92,7 +92,7 @@ LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
    |                                        +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:41
    |
 LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
    |         -                               ^ doesn't have a size known at compile-time
@@ -111,7 +111,7 @@ LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
    |                                         +
 
 error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:23:12
    |
 LL | fn foo5(_: impl ?Sized) {}
    |            ^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:12
    |
 LL | fn foo6(_: impl ?Sized + ?Sized) {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:12
    |
 LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:12
    |
 LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
index e5abcae5d219b..14a2667049775 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
@@ -2,6 +2,6 @@ trait Trait {}
 
 fn test<T: ?self::<i32>::Trait>() {}
 //~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args`
-//~| ERROR relaxing a default bound only does something for `?Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
index dc55b26c9183c..bf968b05af085 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
@@ -1,4 +1,4 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-has-path-args.rs:3:12
    |
 LL | fn test<T: ?self::<i32>::Trait>() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
index 9127c2de16d5e..e123f18474d1c 100644
--- a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
+++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
@@ -2,11 +2,11 @@ trait HasAssoc {
     type Assoc;
 }
 fn hasassoc<T: ?HasAssoc<Assoc = ()>>() {}
-//~^ ERROR relaxing a default bound
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 trait NoAssoc {}
 fn noassoc<T: ?NoAssoc<Missing = ()>>() {}
-//~^ ERROR relaxing a default bound
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 //~| ERROR associated type `Missing` not found for `NoAssoc`
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
index 36a1e0ade2063..b2ae0584aff91 100644
--- a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-with-assoc.rs:4:16
    |
 LL | fn hasassoc<T: ?HasAssoc<Assoc = ()>>() {}
    |                ^^^^^^^^^^^^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-with-assoc.rs:8:15
    |
 LL | fn noassoc<T: ?NoAssoc<Missing = ()>>() {}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs
new file mode 100644
index 0000000000000..47348b0a0dd78
--- /dev/null
+++ b/tests/ui/trait-bounds/more_maybe_bounds.rs
@@ -0,0 +1,29 @@
+// FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`,
+// trying to relax non-default bounds should still be an error in all contexts! As you can see
+// there are places like supertrait bounds and trait object types where we currently don't perform
+// this check.
+#![feature(auto_traits, more_maybe_bounds, negative_impls)]
+
+trait Trait1 {}
+auto trait Trait2 {}
+
+// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
+trait Trait3: ?Trait1 {}
+trait Trait4 where Self: Trait1 {}
+
+// FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`.
+fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
+fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+//~^ ERROR bound modifier `?` can only be applied to default traits like `Sized`
+//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
+//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
+
+struct S;
+impl !Trait2 for S {}
+impl Trait1 for S {}
+impl Trait3 for S {}
+
+fn main() {
+    foo(Box::new(S));
+    bar(&S);
+}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr
new file mode 100644
index 0000000000000..09c9fc311657e
--- /dev/null
+++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr
@@ -0,0 +1,20 @@
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:20
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                    ^^^^^^^
+
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:30
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                              ^^^^^^^
+
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:40
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                                        ^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
index ece87529c3e3b..1d1da9b0e3dfc 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
@@ -14,5 +14,7 @@ fn main() {
 trait NonConst {}
 const fn handle(_: &dyn const NonConst) {}
 //~^ ERROR const trait bounds are not allowed in trait object types
+//~| ERROR `const` can only be applied to `#[const_trait]` traits
 const fn take(_: &dyn [const] NonConst) {}
 //~^ ERROR `[const]` is not allowed here
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
index 090555c637791..06e0493024c1b 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
@@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {}
    |                         ^^^^^^^^^^^^^^
 
 error: `[const]` is not allowed here
-  --> $DIR/const-trait-bounds-trait-objects.rs:17:23
+  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
    |
 LL | const fn take(_: &dyn [const] NonConst) {}
    |                       ^^^^^^^
    |
    = note: trait objects cannot have `[const]` trait bounds
 
-error: aborting due to 4 previous errors
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:15:25
+   |
+LL | const fn handle(_: &dyn const NonConst) {}
+   |                         ^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
+
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
+   |
+LL | const fn take(_: &dyn [const] NonConst) {}
+   |                       ^^^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
index 5f47778a1404f..2df0a133fd613 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
@@ -2,9 +2,12 @@
 
 const fn maybe_const_maybe<T: [const] ?Sized>() {}
 //~^ ERROR `[const]` trait not allowed with `?` trait polarity modifier
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
 
 fn const_maybe<T: const ?Sized>() {}
 //~^ ERROR `const` trait not allowed with `?` trait polarity modifier
+//~| ERROR `const` can only be applied to `#[const_trait]` traits
 
 const fn maybe_const_negative<T: [const] !Trait>() {}
 //~^ ERROR `[const]` trait not allowed with `!` trait polarity modifier
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
index 429131f905f0e..d25c0d2d82bb6 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
@@ -7,7 +7,7 @@ LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
    |                               there is not a well-defined meaning for a `[const] ?` trait
 
 error: `const` trait not allowed with `?` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:25
    |
 LL | fn const_maybe<T: const ?Sized>() {}
    |                   ----- ^
@@ -15,7 +15,7 @@ LL | fn const_maybe<T: const ?Sized>() {}
    |                   there is not a well-defined meaning for a `const ?` trait
 
 error: `[const]` trait not allowed with `!` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42
    |
 LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                  ------- ^
@@ -23,7 +23,7 @@ LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                  there is not a well-defined meaning for a `[const] !` trait
 
 error: `const` trait not allowed with `!` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28
    |
 LL | fn const_negative<T: const !Trait>() {}
    |                      ----- ^
@@ -31,16 +31,44 @@ LL | fn const_negative<T: const !Trait>() {}
    |                      there is not a well-defined meaning for a `const !` trait
 
 error: negative bounds are not supported
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42
    |
 LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                          ^
 
 error: negative bounds are not supported
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28
    |
 LL | fn const_negative<T: const !Trait>() {}
    |                            ^
 
-error: aborting due to 6 previous errors
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
+   |
+LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
+   |                               ^^^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `[const]` can only be applied to `#[const_trait]` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
+   |
+LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
+   |                               ^^^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:19
+   |
+LL | fn const_maybe<T: const ?Sized>() {}
+   |                   ^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
index 5069cd256b277..e7cca41a47eab 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
@@ -64,4 +64,8 @@ fn main() {
     x.leak_foo();
     //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied
     x.maybe_leak_foo();
+    // Ensure that we validate the generic args of relaxed bounds in trait object types.
+    let _: dyn Trait + ?Leak<(), Undefined = ()>;
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR associated type `Undefined` not found for `Leak`
 }
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
index 48745e40268d4..350233b7cbe9d 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
@@ -18,6 +18,27 @@ note: required by a bound in `Trait::leak_foo`
 LL |     fn leak_foo(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
 
-error: aborting due to 2 previous errors
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:68:25
+   |
+LL |     let _: dyn Trait + ?Leak<(), Undefined = ()>;
+   |                         ^^^^-------------------- help: remove the unnecessary generics
+   |                         |
+   |                         expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:44:12
+   |
+LL | auto trait Leak {}
+   |            ^^^^
+
+error[E0220]: associated type `Undefined` not found for `Leak`
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:68:34
+   |
+LL |     let _: dyn Trait + ?Leak<(), Undefined = ()>;
+   |                                  ^^^^^^^^^ associated type `Undefined` not found
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0107, E0220, E0277.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs
deleted file mode 100644
index 1ccd52bc1694a..0000000000000
--- a/tests/ui/traits/maybe-polarity-pass.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#![feature(auto_traits)]
-#![feature(more_maybe_bounds)]
-#![feature(negative_impls)]
-
-trait Trait1 {}
-auto trait Trait2 {}
-
-trait Trait3 : ?Trait1 {}
-trait Trait4 where Self: Trait1 {}
-
-fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
-fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-struct S;
-impl !Trait2 for S {}
-impl Trait1 for S {}
-impl Trait3 for S {}
-
-fn main() {
-    foo(Box::new(S));
-    bar(&S);
-}
diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr
deleted file mode 100644
index 1f378dd665ae6..0000000000000
--- a/tests/ui/traits/maybe-polarity-pass.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:20
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                    ^^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:30
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                              ^^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:40
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                                        ^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs
deleted file mode 100644
index fd1ef567b3eab..0000000000000
--- a/tests/ui/traits/maybe-polarity-repeated.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(more_maybe_bounds)]
-
-trait Trait {}
-fn foo<T: ?Trait + ?Trait>(_: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-fn main() {}
diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr
deleted file mode 100644
index 4fa1dc45bda85..0000000000000
--- a/tests/ui/traits/maybe-polarity-repeated.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/maybe-polarity-repeated.rs:4:11
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |           ^^^^^^   ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-repeated.rs:4:11
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |           ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-repeated.rs:4:20
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |                    ^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0203`.
diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs
deleted file mode 100644
index 04963c98765e9..0000000000000
--- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Test that ?Trait bounds are forbidden in supertraits and trait object types.
-//!
-//! While `?Sized` and other maybe bounds are allowed in type parameter bounds and where clauses,
-//! they are explicitly forbidden in certain syntactic positions:
-//! - As supertraits in trait definitions
-//! - In trait object type expressions
-//!
-//! See https://github.com/rust-lang/rust/issues/20503
-
-trait Tr: ?Sized {}
-//~^ ERROR `?Trait` is not permitted in supertraits
-
-type A1 = dyn Tr + (?Sized);
-//~^ ERROR `?Trait` is not permitted in trait object types
-type A2 = dyn for<'a> Tr + (?Sized);
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-fn main() {}
diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr
deleted file mode 100644
index bd0baa580bdf5..0000000000000
--- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0658]: `?Trait` is not permitted in supertraits
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:10:11
-   |
-LL | trait Tr: ?Sized {}
-   |           ^^^^^^
-   |
-   = note: traits are `?Sized` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:13:20
-   |
-LL | type A1 = dyn Tr + (?Sized);
-   |                    ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:15:28
-   |
-LL | type A2 = dyn for<'a> Tr + (?Sized);
-   |                            ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/wf-object/maybe-bound.rs b/tests/ui/traits/wf-object/maybe-bound.rs
deleted file mode 100644
index 17771e976ef3b..0000000000000
--- a/tests/ui/traits/wf-object/maybe-bound.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects).
-
-trait Foo {}
-
-type _0 = dyn ?Sized + Foo;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-type _1 = dyn Foo + ?Sized;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-type _2 = dyn Foo + ?Sized + ?Sized;
-//~^ ERROR `?Trait` is not permitted in trait object types
-//~| ERROR `?Trait` is not permitted in trait object types
-
-type _3 = dyn ?Sized + Foo;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-fn main() {}
diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr
deleted file mode 100644
index be7afabd0d01d..0000000000000
--- a/tests/ui/traits/wf-object/maybe-bound.stderr
+++ /dev/null
@@ -1,48 +0,0 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:5:15
-   |
-LL | type _0 = dyn ?Sized + Foo;
-   |               ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:8:21
-   |
-LL | type _1 = dyn Foo + ?Sized;
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:11:21
-   |
-LL | type _2 = dyn Foo + ?Sized + ?Sized;
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:11:30
-   |
-LL | type _2 = dyn Foo + ?Sized + ?Sized;
-   |                              ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:15:15
-   |
-LL | type _3 = dyn ?Sized + Foo;
-   |               ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/wf-object/only-maybe-bound.rs b/tests/ui/traits/wf-object/only-maybe-bound.rs
index 3e6db3e997c9b..96360e0331cdb 100644
--- a/tests/ui/traits/wf-object/only-maybe-bound.rs
+++ b/tests/ui/traits/wf-object/only-maybe-bound.rs
@@ -2,6 +2,6 @@
 
 type _0 = dyn ?Sized;
 //~^ ERROR at least one trait is required for an object type [E0224]
-//~| ERROR ?Trait` is not permitted in trait object types
+//~| ERROR relaxed bounds are not permitted in trait object types
 
 fn main() {}
diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr
index 26269476eaaee..d52728e209ec4 100644
--- a/tests/ui/traits/wf-object/only-maybe-bound.stderr
+++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `?Trait` is not permitted in trait object types
+error[E0658]: relaxed bounds are not permitted in trait object types
   --> $DIR/only-maybe-bound.rs:3:15
    |
 LL | type _0 = dyn ?Sized;
diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/maybe-bounds-where.rs
deleted file mode 100644
index 4c4141631a7c5..0000000000000
--- a/tests/ui/unsized/maybe-bounds-where.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-struct S1<T>(T) where (T): ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-struct S2<T>(T) where u8: ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-struct S3<T>(T) where &'static T: ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-trait Trait<'a> {}
-
-struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-//~| ERROR relaxing a default bound only does something for `?Sized`
-
-struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-//~^ ERROR type parameter has more than one relaxed default bound
-//~| ERROR relaxing a default bound only does something for `?Sized`
-
-impl<T> S1<T> {
-    fn f() where T: ?Sized {}
-    //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-}
-
-fn main() {
-    let u = vec![1, 2, 3];
-    let _s: S5<[u8]> = S5(&u[..]); // OK
-}
diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr
deleted file mode 100644
index fb6d37c29660a..0000000000000
--- a/tests/ui/unsized/maybe-bounds-where.stderr
+++ /dev/null
@@ -1,70 +0,0 @@
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:1:28
-   |
-LL | struct S1<T>(T) where (T): ?Sized;
-   |                            ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:4:27
-   |
-LL | struct S2<T>(T) where u8: ?Sized;
-   |                           ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:7:35
-   |
-LL | struct S3<T>(T) where &'static T: ?Sized;
-   |                                   ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:12:34
-   |
-LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-   |                                  ^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:21:21
-   |
-LL |     fn f() where T: ?Sized {}
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-bounds-where.rs:12:34
-   |
-LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-   |                                  ^^^^^^^^^^
-
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/maybe-bounds-where.rs:16:33
-   |
-LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-   |                                 ^^^^^^^^^^^^^^^   ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-bounds-where.rs:16:33
-   |
-LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-   |                                 ^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
-Some errors have detailed explanations: E0203, E0658.
-For more information about an error, try `rustc --explain E0203`.
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
new file mode 100644
index 0000000000000..b8eda1e7786b5
--- /dev/null
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
@@ -0,0 +1,34 @@
+// Test various places where relaxed bounds are not permitted.
+//
+// Relaxed bounds are only permitted inside impl-Trait, assoc ty item bounds and
+// on type params defined by the closest item.
+
+struct S1<T>(T) where (T): ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+struct S2<T>(T) where u8: ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+struct S3<T>(T) where &'static T: ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+trait Trait<'a> {}
+
+struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+//~^ ERROR this relaxed bound is not permitted here
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+
+struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+
+impl<T> S1<T> {
+    fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
+}
+
+trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
+
+// Test that relaxed `Sized` bounds are rejected in trait object types:
+
+type O1 = dyn Tr + ?Sized; //~ ERROR relaxed bounds are not permitted in trait object types
+type O2 = dyn ?Sized + ?Sized + Tr;
+//~^ ERROR relaxed bounds are not permitted in trait object types
+//~| ERROR relaxed bounds are not permitted in trait object types
+
+fn main() {}
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
new file mode 100644
index 0000000000000..46a709f2e9e87
--- /dev/null
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
@@ -0,0 +1,102 @@
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:6:28
+   |
+LL | struct S1<T>(T) where (T): ?Sized;
+   |                            ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:8:27
+   |
+LL | struct S2<T>(T) where u8: ?Sized;
+   |                           ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:10:35
+   |
+LL | struct S3<T>(T) where &'static T: ?Sized;
+   |                                   ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:14:34
+   |
+LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+   |                                  ^^^^^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error[E0658]: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:22:21
+   |
+LL |     fn f() where T: ?Sized {}
+   |                     ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error[E0658]: relaxed bounds are not permitted in supertrait bounds
+  --> $DIR/relaxed-bounds-invalid-places.rs:25:11
+   |
+LL | trait Tr: ?Sized {}
+   |           ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: traits are `?Sized` by default
+
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:29:20
+   |
+LL | type O1 = dyn Tr + ?Sized;
+   |                    ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:30:15
+   |
+LL | type O2 = dyn ?Sized + ?Sized + Tr;
+   |               ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:30:24
+   |
+LL | type O2 = dyn ?Sized + ?Sized + Tr;
+   |                        ^^^^^^
+   |
+   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/relaxed-bounds-invalid-places.rs:14:34
+   |
+LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+   |                                  ^^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/relaxed-bounds-invalid-places.rs:18:33
+   |
+LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
+   |                                 ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0658`.