about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir/src/lang_items.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs61
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs243
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs12
-rw-r--r--compiler/rustc_middle/src/ty/context.rs23
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs42
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs38
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_type_ir/src/interner.rs2
-rw-r--r--tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs25
-rw-r--r--tests/ui/traits/default_auto_traits/default-bounds.rs41
-rw-r--r--tests/ui/traits/default_auto_traits/default-bounds.stderr31
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.current.stderr17
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.next.stderr17
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.rs49
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs61
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr23
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs115
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr71
24 files changed, 829 insertions, 85 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index e625514e9ff..90fab01ba2d 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -433,6 +433,12 @@ language_item_table! {
     // Experimental lang items for implementing contract pre- and post-condition checking.
     ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None;
     ContractCheckRequires,     sym::contract_check_requires,      contract_check_requires_fn,      Target::Fn, GenericRequirement::None;
+
+    // Experimental lang items for `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727)
+    DefaultTrait4,           sym::default_trait4,      default_trait4_trait,       Target::Trait,          GenericRequirement::None;
+    DefaultTrait3,           sym::default_trait3,      default_trait3_trait,       Target::Trait,          GenericRequirement::None;
+    DefaultTrait2,           sym::default_trait2,      default_trait2_trait,       Target::Trait,          GenericRequirement::None;
+    DefaultTrait1,           sym::default_trait1,      default_trait1_trait,       Target::Trait,          GenericRequirement::None;
 }
 
 /// The requirement imposed on the generics of a lang item
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 177243b1b76..7c5d7b33a34 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -341,9 +341,8 @@ fn bounds_from_generic_predicates<'tcx>(
             ty::ClauseKind::Trait(trait_predicate) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
-                if Some(def_id) != tcx.lang_items().sized_trait() {
-                    // Type params are `Sized` by default, do not add that restriction to the list
-                    // if it is a positive requirement.
+                if !tcx.is_default_trait(def_id) {
+                    // Do not add that restriction to the list if it is a positive requirement.
                     entry.push(trait_predicate.def_id());
                 }
             }
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 6e07f0ff53c..279b1e82a71 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -38,13 +38,13 @@ fn associated_type_bounds<'tcx>(
         let icx = ItemCtxt::new(tcx, assoc_item_def_id);
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
-        // Associated types are implicitly sized unless a `?Sized` bound is found
+        // Implicit bounds are added to associated types unless a `?Trait` bound is found
         match filter {
             PredicateFilter::All
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
-                icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+                icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             // `ConstIfConst` is only interested in `~const` bounds.
             PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
@@ -327,14 +327,13 @@ fn opaque_type_bounds<'tcx>(
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
-        // Opaque types are implicitly sized unless a `?Sized` bound is found
+        // Implicit bounds are added to opaque types unless a `?Trait` bound is found
         match filter {
             PredicateFilter::All
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
-                // Associated types are implicitly sized unless a `?Sized` bound is found
-                icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+                icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             //`ConstIfConst` is only interested in `~const` bounds.
             PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 98da8449d5e..776b23bea8e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -165,12 +165,42 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 
             ItemKind::Trait(_, _, _, _, self_bounds, ..)
             | ItemKind::TraitAlias(_, _, self_bounds) => {
-                is_trait = Some(self_bounds);
+                is_trait = Some((self_bounds, item.span));
             }
             _ => {}
         }
     };
 
+    if let Node::TraitItem(item) = node {
+        let parent = tcx.local_parent(item.hir_id().owner.def_id);
+        let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
+            unreachable!();
+        };
+
+        let (trait_generics, trait_bounds) = match parent_trait.kind {
+            hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
+            _ => unreachable!(),
+        };
+
+        // Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
+        // they are not added as super trait bounds to the trait itself. See comment on
+        // `requires_default_supertraits` for more details.
+        if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) {
+            let mut bounds = Vec::new();
+            let self_ty_where_predicates = (parent, item.generics.predicates);
+            icx.lowerer().add_default_traits_with_filter(
+                &mut bounds,
+                tcx.types.self_param,
+                &[],
+                Some(self_ty_where_predicates),
+                item.span,
+                |tr| tr != hir::LangItem::Sized,
+            );
+            predicates.extend(bounds);
+        }
+    }
+
     let generics = tcx.generics_of(def_id);
 
     // Below we'll consider the bounds on the type parameters (including `Self`)
@@ -181,11 +211,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
-            self_bounds,
+            self_bounds.0,
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::All,
         );
+        icx.lowerer().add_default_super_traits(
+            def_id,
+            &mut bounds,
+            self_bounds.0,
+            hir_generics,
+            self_bounds.1,
+        );
         predicates.extend(bounds);
     }
 
@@ -210,8 +247,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             GenericParamKind::Type { .. } => {
                 let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
                 let mut bounds = Vec::new();
-                // Params are implicitly sized unless a `?Sized` bound is found
-                icx.lowerer().add_sized_bound(
+                // Implicit bounds are added to type params unless a `?Trait` bound is found
+                icx.lowerer().add_default_traits(
                     &mut bounds,
                     param_ty,
                     &[],
@@ -625,6 +662,22 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
     let self_param_ty = tcx.types.self_param;
     let mut bounds = Vec::new();
     icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
+    match filter {
+        PredicateFilter::All
+        | PredicateFilter::SelfOnly
+        | PredicateFilter::SelfTraitThatDefines(_)
+        | PredicateFilter::SelfAndAssociatedTypeBounds => {
+            icx.lowerer().add_default_super_traits(
+                trait_def_id,
+                &mut bounds,
+                superbounds,
+                generics,
+                item.span,
+            );
+        }
+        //`ConstIfConst` is only interested in `~const` bounds.
+        PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+    }
 
     let where_bounds_that_match =
         icx.probe_ty_param_bounds_in_generics(generics, item.owner_id.def_id, filter);
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 302abc27324..c3bb860538e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
-use rustc_hir::HirId;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{AmbigArg, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -24,25 +24,190 @@ use crate::hir_ty_lowering::{
 };
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    /// Add a `Sized` bound to the `bounds` if appropriate.
-    ///
-    /// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`.
-    pub(crate) fn add_sized_bound(
+    pub(crate) fn add_default_traits(
         &self,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
+        hir_bounds: &[hir::GenericBound<'tcx>],
+        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+        span: Span,
+    ) {
+        self.add_default_traits_with_filter(
+            bounds,
+            self_ty,
+            hir_bounds,
+            self_ty_where_predicates,
+            span,
+            |_| true,
+        );
+    }
+
+    /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
+    /// or associative items.
+    ///
+    /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
+    /// should be added everywhere, including super bounds. However this causes a huge performance
+    /// costs. For optimization purposes instead of adding default supertraits, bounds
+    /// are added to the associative items:
+    ///
+    /// ```ignore(illustrative)
+    /// // Default bounds are generated in the following way:
+    /// trait Trait {
+    ///     fn foo(&self) where Self: Leak {}
+    /// }
+    ///
+    /// // instead of this:
+    /// trait Trait: Leak {
+    ///     fn foo(&self) {}
+    /// }
+    /// ```
+    /// It is not always possible to do this because of backward compatibility:
+    ///
+    /// ```ignore(illustrative)
+    /// pub trait Trait<Rhs = Self> {}
+    /// pub trait Trait1 : Trait {}
+    /// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait`
+    /// ```
+    ///
+    /// or:
+    ///
+    /// ```ignore(illustrative)
+    /// trait Trait {
+    ///     type Type where Self: Sized;
+    /// }
+    /// trait Trait2<T> : Trait<Type = T> {}
+    /// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit  `Self: DefaultAutoTrait` in `Trait::Type`
+    /// ```
+    ///
+    /// Therefore, `experimental_default_bounds` are still being added to supertraits if
+    /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
+    pub(crate) fn requires_default_supertraits(
+        &self,
         hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+        hir_generics: &'tcx hir::Generics<'tcx>,
+    ) -> bool {
+        struct TraitInfoCollector;
+
+        impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector {
+            type Result = ControlFlow<()>;
+
+            fn visit_assoc_item_constraint(
+                &mut self,
+                _constraint: &'tcx hir::AssocItemConstraint<'tcx>,
+            ) -> Self::Result {
+                ControlFlow::Break(())
+            }
+
+            fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
+                if matches!(
+                    &t.kind,
+                    hir::TyKind::Path(hir::QPath::Resolved(
+                        _,
+                        hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. },
+                    ))
+                ) {
+                    return ControlFlow::Break(());
+                }
+                hir::intravisit::walk_ty(self, t)
+            }
+        }
+
+        let mut found = false;
+        for bound in hir_bounds {
+            found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break();
+        }
+        found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break();
+        found
+    }
+
+    /// Lazily sets `experimental_default_bounds` to true on trait super bounds.
+    /// See `requires_default_supertraits` for more information.
+    pub(crate) fn add_default_super_traits(
+        &self,
+        trait_def_id: LocalDefId,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+        hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+        hir_generics: &'tcx hir::Generics<'tcx>,
+        span: Span,
+    ) {
+        assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
+        if self.requires_default_supertraits(hir_bounds, hir_generics) {
+            let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
+            self.add_default_traits_with_filter(
+                bounds,
+                self.tcx().types.self_param,
+                hir_bounds,
+                Some(self_ty_where_predicates),
+                span,
+                |default_trait| default_trait != hir::LangItem::Sized,
+            );
+        }
+    }
+
+    pub(crate) fn add_default_traits_with_filter(
+        &self,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+        self_ty: Ty<'tcx>,
+        hir_bounds: &[hir::GenericBound<'tcx>],
+        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+        span: Span,
+        f: impl Fn(hir::LangItem) -> bool,
+    ) {
+        self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each(
+            |default_trait| {
+                self.add_default_trait(
+                    *default_trait,
+                    bounds,
+                    self_ty,
+                    hir_bounds,
+                    self_ty_where_predicates,
+                    span,
+                );
+            },
+        );
+    }
+
+    /// Add a `Sized` or `experimental_default_bounds` bounds to the `bounds` if appropriate.
+    ///
+    /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`.
+    pub(crate) fn add_default_trait(
+        &self,
+        trait_: hir::LangItem,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+        self_ty: Ty<'tcx>,
+        hir_bounds: &[hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
     ) {
+        let trait_id = self.tcx().lang_items().get(trait_);
+        if let Some(trait_id) = trait_id
+            && self.do_not_provide_default_trait_bound(
+                trait_id,
+                hir_bounds,
+                self_ty_where_predicates,
+            )
+        {
+            // There was no `?Trait` or `!Trait` bound;
+            // add `Trait` if it's available.
+            let trait_ref = ty::TraitRef::new(self.tcx(), trait_id, [self_ty]);
+            // Preferable to put this obligation first, since we report better errors for sized ambiguity.
+            bounds.insert(0, (trait_ref.upcast(self.tcx()), span));
+        }
+    }
+
+    fn do_not_provide_default_trait_bound<'a>(
+        &self,
+        trait_def_id: DefId,
+        hir_bounds: &'a [hir::GenericBound<'tcx>],
+        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    ) -> bool {
         let tcx = self.tcx();
-        let sized_def_id = tcx.lang_items().sized_trait();
-        let mut seen_negative_sized_bound = false;
-        let mut seen_positive_sized_bound = false;
+        let mut seen_negative_bound = false;
+        let mut seen_positive_bound = false;
 
         // Try to find an unbound in bounds.
         let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
-        let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+        let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'tcx>]| {
             for hir_bound in hir_bounds {
                 let hir::GenericBound::Trait(ptr) = hir_bound else {
                     continue;
@@ -50,17 +215,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 match ptr.modifiers.polarity {
                     hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
                     hir::BoundPolarity::Negative(_) => {
-                        if let Some(sized_def_id) = sized_def_id
-                            && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
-                        {
-                            seen_negative_sized_bound = true;
+                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
+                            seen_negative_bound = true;
                         }
                     }
                     hir::BoundPolarity::Positive => {
-                        if let Some(sized_def_id) = sized_def_id
-                            && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
-                        {
-                            seen_positive_sized_bound = true;
+                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
+                            seen_positive_bound = true;
                         }
                     }
                 }
@@ -95,32 +256,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             };
         }
 
-        let mut seen_sized_unbound = false;
+        let mut seen_unbound = false;
         for unbound in unbounds {
-            if let Some(sized_def_id) = sized_def_id
-                && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
-            {
-                seen_sized_unbound = true;
-                continue;
+            let unbound_def_id = unbound.trait_ref.trait_def_id();
+            if unbound_def_id == Some(trait_def_id) {
+                seen_unbound = true;
+            }
+            let emit_relax_err = || {
+                let unbound_traits =
+                    match self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
+                        true => "`?Sized` and `experimental_default_bounds`",
+                        false => "`?Sized`",
+                    };
+                // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
+                tcx.dcx().span_err(
+                    unbound.span,
+                    format!(
+                        "relaxing a default bound only does something for {}; \
+                    all other traits are not bound by default",
+                        unbound_traits
+                    ),
+                );
+            };
+            match unbound_def_id {
+                Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_err(),
+                None => emit_relax_err(),
+                _ => {}
             }
-            // There was a `?Trait` bound, but it was not `?Sized`
-            self.dcx().span_err(
-                unbound.span,
-                "relaxing a default bound only does something for `?Sized`; \
-                all other traits are not bound by default",
-            );
         }
 
-        if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
-            // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
-            // we don't need to do anything.
-        } else if let Some(sized_def_id) = sized_def_id {
-            // There was no `?Sized`, `!Sized` or explicit `Sized` bound;
-            // add `Sized` if it's available.
-            let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [self_ty]);
-            // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-            bounds.insert(0, (trait_ref.upcast(tcx), span));
-        }
+        !(seen_unbound || seen_negative_bound || seen_positive_bound)
     }
 
     /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
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 27643e715e6..aeebe45f881 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
@@ -57,6 +57,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        let ast_bounds: Vec<_> =
+            hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
+
+        self.add_default_traits_with_filter(
+            &mut user_written_bounds,
+            dummy_self,
+            &ast_bounds,
+            None,
+            span,
+            |tr| tr != hir::LangItem::Sized,
+        );
+
         let (elaborated_trait_bounds, elaborated_projection_bounds) =
             traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
         let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f064bdb2576..13217ae58e9 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -446,6 +446,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
     }
 
+    fn is_default_trait(self, def_id: DefId) -> bool {
+        self.is_default_trait(def_id)
+    }
+
     fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
         lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
     }
@@ -1539,6 +1543,25 @@ impl<'tcx> TyCtxt<'tcx> {
         self.reserve_and_set_memory_dedup(alloc, salt)
     }
 
+    pub fn default_traits(self) -> &'static [rustc_hir::LangItem] {
+        match self.sess.opts.unstable_opts.experimental_default_bounds {
+            true => &[
+                LangItem::Sized,
+                LangItem::DefaultTrait1,
+                LangItem::DefaultTrait2,
+                LangItem::DefaultTrait3,
+                LangItem::DefaultTrait4,
+            ],
+            false => &[LangItem::Sized],
+        }
+    }
+
+    pub fn is_default_trait(self, def_id: DefId) -> bool {
+        self.default_traits()
+            .iter()
+            .any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
+    }
+
     /// Returns a range of the start/end indices specified with the
     /// `rustc_layout_scalar_valid_range` attribute.
     // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index a5142de2d39..c2fb592c3f3 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -37,12 +37,16 @@ where
         | ty::Never
         | ty::Char => Ok(ty::Binder::dummy(vec![])),
 
+        // This branch is only for `experimental_default_bounds`.
+        // Other foreign types were rejected earlier in
+        // `disqualify_auto_trait_candidate_due_to_possible_impl`.
+        ty::Foreign(..) => Ok(ty::Binder::dummy(vec![])),
+
         // Treat `str` like it's defined as `struct str([u8]);`
         ty::Str => Ok(ty::Binder::dummy(vec![Ty::new_slice(cx, Ty::new_u8(cx))])),
 
         ty::Dynamic(..)
         | ty::Param(..)
-        | ty::Foreign(..)
         | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
         | ty::Placeholder(..)
         | ty::Bound(..)
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index b72f776e5cb..b7ae96ec9d2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1086,6 +1086,25 @@ where
         goal: Goal<I, TraitPredicate<I>>,
     ) -> Option<Result<Candidate<I>, NoSolution>> {
         let self_ty = goal.predicate.self_ty();
+        let check_impls = || {
+            let mut disqualifying_impl = None;
+            self.cx().for_each_relevant_impl(
+                goal.predicate.def_id(),
+                goal.predicate.self_ty(),
+                |impl_def_id| {
+                    disqualifying_impl = Some(impl_def_id);
+                },
+            );
+            if let Some(def_id) = disqualifying_impl {
+                trace!(?def_id, ?goal, "disqualified auto-trait implementation");
+                // No need to actually consider the candidate here,
+                // since we do that in `consider_impl_candidate`.
+                return Some(Err(NoSolution));
+            } else {
+                None
+            }
+        };
+
         match self_ty.kind() {
             // Stall int and float vars until they are resolved to a concrete
             // numerical type. That's because the check for impls below treats
@@ -1096,6 +1115,10 @@ where
                 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
             }
 
+            // Backward compatibility for default auto traits.
+            // Test: ui/traits/default_auto_traits/extern-types.rs
+            ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
+
             // These types cannot be structurally decomposed into constituent
             // types, and therefore have no built-in auto impl.
             ty::Dynamic(..)
@@ -1156,24 +1179,7 @@ where
             | ty::Never
             | ty::Tuple(_)
             | ty::Adt(_, _)
-            | ty::UnsafeBinder(_) => {
-                let mut disqualifying_impl = None;
-                self.cx().for_each_relevant_impl(
-                    goal.predicate.def_id(),
-                    goal.predicate.self_ty(),
-                    |impl_def_id| {
-                        disqualifying_impl = Some(impl_def_id);
-                    },
-                );
-                if let Some(def_id) = disqualifying_impl {
-                    trace!(?def_id, ?goal, "disqualified auto-trait implementation");
-                    // No need to actually consider the candidate here,
-                    // since we do that in `consider_impl_candidate`.
-                    return Some(Err(NoSolution));
-                } else {
-                    None
-                }
-            }
+            | ty::UnsafeBinder(_) => check_impls(),
             ty::Error(_) => None,
         }
     }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index cd5e2c4173e..eb513e00936 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2187,6 +2187,8 @@ options! {
         "Use WebAssembly error handling for wasm32-unknown-emscripten"),
     enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
         "enforce the type length limit when monomorphizing instances in codegen"),
+    experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
+        "enable default bounds for experimental group of auto traits"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
         "export symbols from executables, as if they were dynamic libraries"),
     external_clangrt: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f4996c27805..31847ae3b46 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -800,6 +800,15 @@ symbols! {
         default_fn,
         default_lib_allocator,
         default_method_body_is_const,
+        // --------------------------
+        // Lang items which are used only for experiments with auto traits with default bounds.
+        // These lang items are not actually defined in core/std. Experiment is a part of
+        // `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727)
+        default_trait1,
+        default_trait2,
+        default_trait3,
+        default_trait4,
+        // --------------------------
         default_type_parameter_fallback,
         default_type_params,
         define_opaque,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index d15c9afef3a..cf6d2bc151f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -692,6 +692,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let def_id = obligation.predicate.def_id();
 
+        let mut check_impls = || {
+            // Only consider auto impls if there are no manual impls for the root of `self_ty`.
+            //
+            // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
+            // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls
+            // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined.
+            //
+            // Generally, we have to guarantee that for all `SimplifiedType`s the only crate
+            // which may define impls for that type is either the crate defining the type
+            // or the trait. This should be guaranteed by the orphan check.
+            let mut has_impl = false;
+            self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true);
+            if !has_impl {
+                candidates.vec.push(AutoImplCandidate)
+            }
+        };
+
         if self.tcx().trait_is_auto(def_id) {
             match *self_ty.kind() {
                 ty::Dynamic(..) => {
@@ -705,6 +722,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     // we don't add any `..` impl. Default traits could
                     // still be provided by a manual implementation for
                     // this trait and type.
+
+                    // Backward compatibility for default auto traits.
+                    // Test: ui/traits/default_auto_traits/extern-types.rs
+                    if self.tcx().is_default_trait(def_id) {
+                        check_impls()
+                    }
                 }
                 ty::Param(..)
                 | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
@@ -805,20 +828,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         return;
                     }
 
-                    // Only consider auto impls if there are no manual impls for the root of `self_ty`.
-                    //
-                    // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
-                    // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls
-                    // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined.
-                    //
-                    // Generally, we have to guarantee that for all `SimplifiedType`s the only crate
-                    // which may define impls for that type is either the crate defining the type
-                    // or the trait. This should be guaranteed by the orphan check.
-                    let mut has_impl = false;
-                    self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true);
-                    if !has_impl {
-                        candidates.vec.push(AutoImplCandidate)
-                    }
+                    check_impls();
                 }
                 ty::Error(_) => {
                     candidates.vec.push(AutoImplCandidate);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0679dbf1296..42c598e538d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2299,6 +2299,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Never
             | ty::Char => ty::Binder::dummy(Vec::new()),
 
+            // This branch is only for `experimental_default_bounds`.
+            // Other foreign types were rejected earlier in
+            // `assemble_candidates_from_auto_impls`.
+            ty::Foreign(..) => ty::Binder::dummy(Vec::new()),
+
             // FIXME(unsafe_binders): Squash the double binder for now, I guess.
             ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
 
@@ -2308,7 +2313,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ty::Placeholder(..)
             | ty::Dynamic(..)
             | ty::Param(..)
-            | ty::Foreign(..)
             | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
             | ty::Bound(..)
             | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 8f86270d7dc..ff0d8cdd585 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -259,6 +259,8 @@ pub trait Interner:
 
     fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
 
+    fn is_default_trait(self, def_id: Self::DefId) -> bool;
+
     fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;
 
     fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
diff --git a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs
new file mode 100644
index 00000000000..3818456d3a6
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs
@@ -0,0 +1,25 @@
+//@ check-pass
+//@ compile-flags: -Zexperimental-default-bounds
+
+#![feature(auto_traits, lang_items, no_core, rustc_attrs, trait_alias)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "default_trait1"]
+auto trait DefaultTrait1 {}
+
+#[lang = "default_trait2"]
+auto trait DefaultTrait2 {}
+
+trait Trait<Rhs: ?Sized = Self> {}
+trait Trait1 : Trait {}
+
+trait Trait2 {
+    type Type;
+}
+trait Trait3<T> = Trait2<Type = T>;
+
+fn main() {}
diff --git a/tests/ui/traits/default_auto_traits/default-bounds.rs b/tests/ui/traits/default_auto_traits/default-bounds.rs
new file mode 100644
index 00000000000..64733a40034
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/default-bounds.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -Zexperimental-default-bounds
+
+#![feature(
+    auto_traits,
+    lang_items,
+    negative_impls,
+    no_core,
+    rustc_attrs
+)]
+#![allow(incomplete_features)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "default_trait1"]
+auto trait Leak {}
+
+#[lang = "default_trait2"]
+auto trait SyncDrop {}
+
+struct Forbidden;
+
+impl !Leak for Forbidden {}
+impl !SyncDrop for Forbidden {}
+
+struct Accepted;
+
+fn bar<T: Leak>(_: T) {}
+
+fn main() {
+    // checking that bounds can be added explicitly
+    bar(Forbidden);
+    //~^ ERROR the trait bound `Forbidden: Leak` is not satisfied
+    //~| ERROR the trait bound `Forbidden: SyncDrop` is not satisfied
+    bar(Accepted);
+}
diff --git a/tests/ui/traits/default_auto_traits/default-bounds.stderr b/tests/ui/traits/default_auto_traits/default-bounds.stderr
new file mode 100644
index 00000000000..10fdcc43417
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/default-bounds.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied
+  --> $DIR/default-bounds.rs:37:9
+   |
+LL |     bar(Forbidden);
+   |     --- ^^^^^^^^^ the trait `SyncDrop` is not implemented for `Forbidden`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bar`
+  --> $DIR/default-bounds.rs:33:8
+   |
+LL | fn bar<T: Leak>(_: T) {}
+   |        ^ required by this bound in `bar`
+
+error[E0277]: the trait bound `Forbidden: Leak` is not satisfied
+  --> $DIR/default-bounds.rs:37:9
+   |
+LL |     bar(Forbidden);
+   |     --- ^^^^^^^^^ the trait `Leak` is not implemented for `Forbidden`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bar`
+  --> $DIR/default-bounds.rs:33:11
+   |
+LL | fn bar<T: Leak>(_: T) {}
+   |           ^^^^ required by this bound in `bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/default_auto_traits/extern-types.current.stderr b/tests/ui/traits/default_auto_traits/extern-types.current.stderr
new file mode 100644
index 00000000000..e1bd99b900f
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/extern-types.current.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
+  --> $DIR/extern-types.rs:44:13
+   |
+LL |         foo(x);
+   |         --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
+   |         |
+   |         required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/extern-types.rs:20:8
+   |
+LL | fn foo<T: ?Sized>(_: &T) {}
+   |        ^ required by this bound in `foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/default_auto_traits/extern-types.next.stderr b/tests/ui/traits/default_auto_traits/extern-types.next.stderr
new file mode 100644
index 00000000000..e1bd99b900f
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/extern-types.next.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
+  --> $DIR/extern-types.rs:44:13
+   |
+LL |         foo(x);
+   |         --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
+   |         |
+   |         required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/extern-types.rs:20:8
+   |
+LL | fn foo<T: ?Sized>(_: &T) {}
+   |        ^ required by this bound in `foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/default_auto_traits/extern-types.rs b/tests/ui/traits/default_auto_traits/extern-types.rs
new file mode 100644
index 00000000000..822d4c0637f
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/extern-types.rs
@@ -0,0 +1,49 @@
+//@  compile-flags:  -Zexperimental-default-bounds
+//@ revisions: current next
+//@ [next] compile-flags: -Znext-solver
+
+#![feature(auto_traits, extern_types, lang_items, negative_impls, no_core, rustc_attrs)]
+#![allow(incomplete_features)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "default_trait1"]
+auto trait Leak {}
+
+// implicit T: Leak here
+fn foo<T: ?Sized>(_: &T) {}
+
+mod extern_leak {
+    use crate::*;
+
+    extern "C" {
+        type Opaque;
+    }
+
+    fn forward_extern_ty(x: &Opaque) {
+        // ok, extern type leak by default
+        crate::foo(x);
+    }
+}
+
+mod extern_non_leak {
+    use crate::*;
+
+    extern "C" {
+        type Opaque;
+    }
+
+    impl !Leak for Opaque {}
+    fn forward_extern_ty(x: &Opaque) {
+        foo(x);
+        //~^ ERROR: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
+    }
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..49f2faba146
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
@@ -0,0 +1,61 @@
+//@ compile-flags: -Zexperimental-default-bounds
+
+#![feature(
+    auto_traits,
+    lang_items,
+    more_maybe_bounds,
+    negative_impls,
+    no_core,
+    rustc_attrs
+)]
+#![allow(internal_features)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+pub trait Copy {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+
+#[lang = "legacy_receiver"]
+trait Receiver {}
+impl<T: ?Sized + ?Leak> Receiver for &T {}
+
+#[lang = "unsize"]
+trait Unsize<T: ?Sized + ?Leak> {}
+
+#[lang = "coerce_unsized"]
+trait CoerceUnsized<T: ?Leak + ?Sized> {}
+impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {}
+
+#[lang = "dispatch_from_dyn"]
+trait DispatchFromDyn<T: ?Leak> {}
+impl<'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {}
+
+#[lang = "default_trait1"]
+auto trait Leak {}
+
+struct NonLeakS;
+impl !Leak for NonLeakS {}
+struct LeakS;
+
+trait Trait {
+    fn leak_foo(&self) {}
+    fn maybe_leak_foo(&self) where Self: ?Leak {}
+}
+
+impl Trait for NonLeakS {}
+impl Trait for LeakS {}
+
+fn main() {
+    let _: &dyn Trait = &NonLeakS;
+    //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
+    let _: &dyn Trait = &LeakS;
+    let _: &(dyn Trait + ?Leak) = &LeakS;
+    let x: &(dyn Trait + ?Leak) = &NonLeakS;
+    x.leak_foo();
+    //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied
+    x.maybe_leak_foo();
+}
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
new file mode 100644
index 00000000000..b7ffb66e60b
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:53:25
+   |
+LL |     let _: &dyn Trait = &NonLeakS;
+   |                         ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
+   |
+   = note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak`
+
+error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:58:7
+   |
+LL |     x.leak_foo();
+   |       ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait`
+   |
+note: required by a bound in `Trait::leak_foo`
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:45:5
+   |
+LL |     fn leak_foo(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
new file mode 100644
index 00000000000..761f22d1be5
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
@@ -0,0 +1,115 @@
+//@ compile-flags: -Zexperimental-default-bounds
+
+#![feature(
+    auto_traits,
+    associated_type_defaults,
+    generic_const_items,
+    lang_items,
+    more_maybe_bounds,
+    negative_impls,
+    no_core,
+    rustc_attrs
+)]
+#![allow(incomplete_features)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
+impl<T: ?Sized + ?Leak> LegacyReceiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
+
+#[lang = "default_trait1"]
+auto trait Leak {}
+
+struct NonLeakS;
+impl !Leak for NonLeakS {}
+struct LeakS;
+
+mod supertraits {
+    use crate::*;
+
+    trait MaybeLeakT1: ?Leak {}
+    trait MaybeLeakT2 where Self: ?Leak {}
+
+    impl MaybeLeakT1 for NonLeakS {}
+    impl MaybeLeakT2 for NonLeakS {}
+}
+
+mod maybe_self_assoc_type {
+    use crate::*;
+
+    trait TestBase1<T: ?Sized> {}
+    trait TestBase2<T: ?Leak + ?Sized> {}
+
+    trait Test1<T> {
+        type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
+        //~^ ERROR the trait bound `Self: Leak` is not satisfied
+        type LeakSelf: TestBase1<Self>;
+    }
+
+    trait Test2<T> {
+        type MaybeLeakSelf: TestBase2<Self> where Self: ?Leak;
+        type LeakSelf: TestBase2<Self>;
+    }
+
+    trait Test3 {
+        type Leak1 = LeakS;
+        type Leak2 = NonLeakS;
+        //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
+    }
+
+    trait Test4 {
+        type MaybeLeak1: ?Leak = LeakS;
+        type MaybeLeak2: ?Leak = NonLeakS;
+    }
+
+    trait Test5: ?Leak {
+        // ok, because assoc types have implicit where Self: Leak
+        type MaybeLeakSelf1: TestBase1<Self>;
+        type MaybeLeakSelf2: TestBase2<Self>;
+    }
+}
+
+mod maybe_self_assoc_const {
+    use crate::*;
+
+    const fn size_of<T: ?Sized>() -> usize {
+        0
+    }
+
+    trait Trait {
+        const CLeak: usize = size_of::<Self>();
+        const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
+        //~^ ERROR the trait bound `Self: Leak` is not satisfied
+    }
+}
+
+mod methods {
+    use crate::*;
+
+    trait Trait {
+        fn leak_foo(&self) {}
+        fn maybe_leak_foo(&self) where Self: ?Leak {}
+        fn mut_leak_foo(&mut self) {}
+        // there is no relax bound on corresponding Receiver impl
+        fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
+        //~^  `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types`
+    }
+
+    impl Trait for NonLeakS {}
+    impl Trait for LeakS {}
+
+    fn foo() {
+        LeakS.leak_foo();
+        LeakS.maybe_leak_foo();
+        NonLeakS.leak_foo();
+        //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
+        NonLeakS.maybe_leak_foo();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr
new file mode 100644
index 00000000000..3dd8418b100
--- /dev/null
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr
@@ -0,0 +1,71 @@
+error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-traits.rs:61:22
+   |
+LL |         type Leak2 = NonLeakS;
+   |                      ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
+   |
+note: required by a bound in `Test3::Leak2`
+  --> $DIR/maybe-bounds-in-traits.rs:61:9
+   |
+LL |         type Leak2 = NonLeakS;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2`
+
+error[E0277]: the trait bound `Self: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-traits.rs:49:29
+   |
+LL |         type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
+   |                             ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self`
+   |
+note: required by a bound in `TestBase1`
+  --> $DIR/maybe-bounds-in-traits.rs:45:21
+   |
+LL |     trait TestBase1<T: ?Sized> {}
+   |                     ^ required by this bound in `TestBase1`
+help: consider further restricting `Self`
+   |
+LL |     trait Test1<T>: Leak {
+   |                   ++++++
+
+error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+  --> $DIR/maybe-bounds-in-traits.rs:99:31
+   |
+LL |         fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
+   |                               ^^^^^^^^^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
+
+error[E0277]: the trait bound `Self: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-traits.rs:86:43
+   |
+LL |         const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
+   |                                           ^^^^ the trait `Leak` is not implemented for `Self`
+   |
+note: required by a bound in `size_of`
+  --> $DIR/maybe-bounds-in-traits.rs:80:22
+   |
+LL |     const fn size_of<T: ?Sized>() -> usize {
+   |                      ^ required by this bound in `size_of`
+help: consider further restricting `Self`
+   |
+LL |     trait Trait: Leak {
+   |                ++++++
+
+error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
+  --> $DIR/maybe-bounds-in-traits.rs:109:18
+   |
+LL |         NonLeakS.leak_foo();
+   |                  ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
+   |
+note: required by a bound in `methods::Trait::leak_foo`
+  --> $DIR/maybe-bounds-in-traits.rs:95:9
+   |
+LL |         fn leak_foo(&self) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.