about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs12
-rw-r--r--compiler/rustc_borrowck/src/handle_placeholders.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs13
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs8
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs74
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs17
-rw-r--r--tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr18
-rw-r--r--tests/ui/async-await/drop-live-upvar-2.rs37
-rw-r--r--tests/ui/async-await/drop-live-upvar.rs23
-rw-r--r--tests/ui/async-await/drop-live-upvar.stderr22
-rw-r--r--tests/ui/async-await/recursive-async-auto-trait-overflow.rs14
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-print.rs2
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-print.stderr6
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-println.rs2
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-println.stderr6
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.rs8
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.stderr6
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.rs4
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.stderr18
22 files changed, 239 insertions, 82 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 64c1b53f633..465d9dc82bc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
 enum RelaxedBoundForbiddenReason {
     TraitObjectTy,
     SuperTrait,
+    AssocTyBounds,
     LateBoundVarsInScope,
 }
 
@@ -1109,9 +1110,11 @@ 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 {
-                    // FIXME(#135229): These should be forbidden!
-                    let bounds =
-                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
+                    let bounds = self.lower_param_bounds(
+                        bounds,
+                        RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::AssocTyBounds),
+                        itctx,
+                    );
                     hir::AssocItemConstraintKind::Bound { bounds }
                 }
             }
@@ -2124,7 +2127,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         diag.emit();
                         return;
                     }
-                    RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
+                    RelaxedBoundForbiddenReason::AssocTyBounds
+                    | RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
                 };
             }
         }
diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs
index e168b819a8d..34599ac55b8 100644
--- a/compiler/rustc_borrowck/src/handle_placeholders.rs
+++ b/compiler/rustc_borrowck/src/handle_placeholders.rs
@@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
     for info in var_infos.iter() {
         let origin = match info.origin {
             RegionVariableOrigin::Nll(origin) => origin,
-            _ => NllRegionVariableOrigin::Existential { from_forall: false, name: None },
+            _ => NllRegionVariableOrigin::Existential { name: None },
         };
 
         let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index dbd245214a2..b0c31ac9601 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1939,10 +1939,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         //
         // and here we prefer to blame the source (the y = x statement).
         let blame_source = match from_region_origin {
-            NllRegionVariableOrigin::FreeRegion
-            | NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true,
-            NllRegionVariableOrigin::Placeholder(_)
-            | NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false,
+            NllRegionVariableOrigin::FreeRegion => true,
+            NllRegionVariableOrigin::Placeholder(_) => false,
+            // `'existential: 'whatever` never results in a region error by itself.
+            // We may always infer it to `'static` afterall. This means while an error
+            // path may go through an existential, these existentials are never the
+            // `from_region`.
+            NllRegionVariableOrigin::Existential { name: _ } => {
+                unreachable!("existentials can outlive everything")
+            }
         };
 
         // To pick a constraint to blame, we organize constraints by how interesting we expect them
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 100d30704b9..fa3064afee8 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
         T: TypeFoldable<TyCtxt<'tcx>>,
         F: Fn() -> RegionCtxt,
     {
-        let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None };
+        let origin = NllRegionVariableOrigin::Existential { name: None };
         fold_regions(self.infcx.tcx, value, |_region, _depth| {
             self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
         })
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 393adafea0b..84ca9bad2c1 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
                     *ex_reg_var
                 } else {
                     let ex_reg_var =
-                        self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
+                        self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
                     debug!(?ex_reg_var);
                     reg_map.insert(br, ex_reg_var);
 
@@ -244,17 +244,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn next_existential_region_var(
-        &mut self,
-        from_forall: bool,
-        name: Option<Symbol>,
-    ) -> ty::Region<'tcx> {
-        let origin = NllRegionVariableOrigin::Existential { name, from_forall };
-
-        let reg_var =
-            self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
-
-        reg_var
+    fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
+        let origin = NllRegionVariableOrigin::Existential { name };
+        self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
     }
 
     #[instrument(skip(self), level = "debug")]
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 386e1091ac4..d14aef8ace4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -199,12 +199,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             //        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(more_maybe_bounds): We don't call this for trait object tys, supertrait
+            //                                  bounds or associated type bounds (ATB)!
             //        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).
+            //                                     AST lowering should reject them outright.
             let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
             self.check_and_report_invalid_relaxed_bounds(bounds);
         }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a2afdc45fa8..82d4856df39 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -485,17 +485,6 @@ pub enum NllRegionVariableOrigin {
 
     Existential {
         name: Option<Symbol>,
-        /// If this is true, then this variable was created to represent a lifetime
-        /// bound in a `for` binder. For example, it might have been created to
-        /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
-        /// Such variables are created when we are trying to figure out if there
-        /// is any valid instantiation of `'a` that could fit into some scenario.
-        ///
-        /// This is used to inform error reporting: in the case that we are trying to
-        /// determine whether there is any valid instantiation of a `'a` variable that meets
-        /// some constraint C, we want to blame the "source" of that `for` type,
-        /// rather than blaming the source of the constraint C.
-        from_forall: bool,
     },
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index b1b331d1b61..de404532899 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -319,39 +319,65 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
         }
 
         ty::Coroutine(def_id, args) => {
-            // rust-lang/rust#49918: types can be constructed, stored
-            // in the interior, and sit idle when coroutine yields
-            // (and is subsequently dropped).
+            // rust-lang/rust#49918: Locals can be stored across await points in the coroutine,
+            // called interior/witness types. Since we do not compute these witnesses until after
+            // building MIR, we consider all coroutines to unconditionally require a drop during
+            // MIR building. However, considering the coroutine to unconditionally require a drop
+            // here may unnecessarily require its upvars' regions to be live when they don't need
+            // to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>.
             //
-            // It would be nice to descend into interior of a
-            // coroutine to determine what effects dropping it might
-            // have (by looking at any drop effects associated with
-            // its interior).
+            // Here, we implement a more precise approximation for the coroutine's dtorck constraint
+            // by considering whether any of the interior types needs drop. Note that this is still
+            // an approximation because the coroutine interior has its regions erased, so we must add
+            // *all* of the upvars to live types set if we find that *any* interior type needs drop.
+            // This is because any of the regions captured in the upvars may be stored in the interior,
+            // which then has its regions replaced by a binder (conceptually erasing the regions),
+            // so there's no way to enforce that the precise region in the interior type is live
+            // since we've lost that information by this point.
             //
-            // However, the interior's representation uses things like
-            // CoroutineWitness that explicitly assume they are not
-            // traversed in such a manner. So instead, we will
-            // simplify things for now by treating all coroutines as
-            // if they were like trait objects, where its upvars must
-            // all be alive for the coroutine's (potential)
-            // destructor.
+            // Note also that this check requires that the coroutine's upvars are use-live, since
+            // a region from a type that does not have a destructor that was captured in an upvar
+            // may flow into an interior type with a destructor. This is stronger than requiring
+            // the upvars are drop-live.
             //
-            // In particular, skipping over `_interior` is safe
-            // because any side-effects from dropping `_interior` can
-            // only take place through references with lifetimes
-            // derived from lifetimes attached to the upvars and resume
-            // argument, and we *do* incorporate those here.
+            // For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type
+            // in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the
+            // region `'r` came from the `'1` or `'2` region, so we require both are live. This
+            // could even be unnecessary if `'r` was actually a `'static` region or some region
+            // local to the coroutine! That's why it's an approximation.
             let args = args.as_coroutine();
 
-            // While we conservatively assume that all coroutines require drop
-            // to avoid query cycles during MIR building, we can check the actual
-            // witness during borrowck to avoid unnecessary liveness constraints.
+            // Note that we don't care about whether the resume type has any drops since this is
+            // redundant; there is no storage for the resume type, so if it is actually stored
+            // in the interior, we'll already detect the need for a drop by checking the interior.
             let typing_env = tcx.erase_regions(typing_env);
-            if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
+            let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
                 witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env))
-            }) {
+            });
+            if needs_drop {
+                // Pushing types directly to `constraints.outlives` is equivalent
+                // to requiring them to be use-live, since if we were instead to
+                // recurse on them like we do below, we only end up collecting the
+                // types that are relevant for drop-liveness.
                 constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
                 constraints.outlives.push(args.resume_ty().into());
+            } else {
+                // Even if a witness type doesn't need a drop, we still require that
+                // the upvars are drop-live. This is only needed if we aren't already
+                // counting *all* of the upvars as use-live above, since use-liveness
+                // is a *stronger requirement* than drop-liveness. Recursing here
+                // unconditionally would just be collecting duplicated types for no
+                // reason.
+                for ty in args.upvar_tys() {
+                    dtorck_constraint_for_ty_inner(
+                        tcx,
+                        typing_env,
+                        span,
+                        depth + 1,
+                        ty,
+                        constraints,
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7ea1548f8f2..468c42abf48 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2333,10 +2333,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             ty::Coroutine(def_id, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+                let tcx = self.tcx();
                 let witness = Ty::new_coroutine_witness(
-                    self.tcx(),
+                    tcx,
                     def_id,
-                    self.tcx().mk_args(args.as_coroutine().parent_args()),
+                    ty::GenericArgs::for_item(tcx, def_id, |def, _| match def.kind {
+                        // HACK: Coroutine witnesse types are lifetime erased, so they
+                        // never reference any lifetime args from the coroutine. We erase
+                        // the regions here since we may get into situations where a
+                        // coroutine is recursively contained within itself, leading to
+                        // witness types that differ by region args. This means that
+                        // cycle detection in fulfillment will not kick in, which leads
+                        // to unnecessary overflows in async code. See the issue:
+                        // <https://github.com/rust-lang/rust/issues/145151>.
+                        ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                        ty::GenericParamDefKind::Type { .. }
+                        | ty::GenericParamDefKind::Const { .. } => args[def.index as usize],
+                    }),
                 );
                 ty::Binder::dummy(AutoImplConstituents {
                     types: [ty].into_iter().chain(iter::once(witness)).collect(),
diff --git a/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
new file mode 100644
index 00000000000..34f6ba79246
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/drop-live-upvar-2.rs:31:26
+   |
+LL |         let y = ();
+   |             - binding `y` declared here
+LL |         drop_me = Droppy(&y);
+   |                          ^^ borrowed value does not live long enough
+...
+LL |     }
+   |     - `y` dropped here while still borrowed
+LL | }
+   | - borrow might be used here, when `fut` is dropped and runs the destructor for coroutine
+   |
+   = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/async-await/drop-live-upvar-2.rs b/tests/ui/async-await/drop-live-upvar-2.rs
new file mode 100644
index 00000000000..605db4c8f76
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar-2.rs
@@ -0,0 +1,37 @@
+//@ revisions: may_dangle may_not_dangle
+//@[may_dangle] check-pass
+//@ edition: 2018
+
+// Ensure that if a coroutine's interior has no drop types then we don't require the upvars to
+// be *use-live*, but instead require them to be *drop-live*. In this case, `Droppy<&'?0 ()>`
+// does not require that `'?0` is live for drops since the parameter is `#[may_dangle]` in
+// the may_dangle revision, but not in the may_not_dangle revision.
+
+#![feature(dropck_eyepatch)]
+
+struct Droppy<T>(T);
+
+#[cfg(may_dangle)]
+unsafe impl<#[may_dangle] T> Drop for Droppy<T> {
+    fn drop(&mut self) {
+        // This does not use `T` of course.
+    }
+}
+
+#[cfg(may_not_dangle)]
+impl<T> Drop for Droppy<T> {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    let drop_me;
+    let fut;
+    {
+        let y = ();
+        drop_me = Droppy(&y);
+        //[may_not_dangle]~^ ERROR `y` does not live long enough
+        fut = async {
+            std::mem::drop(drop_me);
+        };
+    }
+}
diff --git a/tests/ui/async-await/drop-live-upvar.rs b/tests/ui/async-await/drop-live-upvar.rs
new file mode 100644
index 00000000000..8e881f729b9
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar.rs
@@ -0,0 +1,23 @@
+//@ edition: 2018
+// Regression test for <https://github.com/rust-lang/rust/issues/144155>.
+
+struct NeedsDrop<'a>(&'a Vec<i32>);
+
+async fn await_point() {}
+
+impl Drop for NeedsDrop<'_> {
+    fn drop(&mut self) {}
+}
+
+fn foo() {
+    let v = vec![1, 2, 3];
+    let x = NeedsDrop(&v);
+    let c = async {
+        std::future::ready(()).await;
+        drop(x);
+    };
+    drop(v);
+    //~^ ERROR cannot move out of `v` because it is borrowed
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/drop-live-upvar.stderr b/tests/ui/async-await/drop-live-upvar.stderr
new file mode 100644
index 00000000000..f804484536b
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar.stderr
@@ -0,0 +1,22 @@
+error[E0505]: cannot move out of `v` because it is borrowed
+  --> $DIR/drop-live-upvar.rs:19:10
+   |
+LL |     let v = vec![1, 2, 3];
+   |         - binding `v` declared here
+LL |     let x = NeedsDrop(&v);
+   |                       -- borrow of `v` occurs here
+...
+LL |     drop(v);
+   |          ^ move out of `v` occurs here
+LL |
+LL | }
+   | - borrow might be used here, when `c` is dropped and runs the destructor for coroutine
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let x = NeedsDrop(&v.clone());
+   |                         ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/async-await/recursive-async-auto-trait-overflow.rs b/tests/ui/async-await/recursive-async-auto-trait-overflow.rs
new file mode 100644
index 00000000000..716600ce472
--- /dev/null
+++ b/tests/ui/async-await/recursive-async-auto-trait-overflow.rs
@@ -0,0 +1,14 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/145151>.
+
+//@ edition: 2024
+//@ check-pass
+
+async fn process<'a>() {
+    Box::pin(process()).await;
+}
+
+fn require_send(_: impl Send) {}
+
+fn main() {
+    require_send(process());
+}
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.rs b/tests/ui/infinite/issue-41731-infinite-macro-print.rs
index 7cd3ff3d629..aa5555b117a 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-print.rs
+++ b/tests/ui/infinite/issue-41731-infinite-macro-print.rs
@@ -5,7 +5,7 @@
 fn main() {
     macro_rules! stack {
         ($overflow:expr) => {
-            print!(stack!($overflow));
+            print!(stack!($overflow))
             //~^ ERROR recursion limit reached while expanding
             //~| ERROR format argument must be a string literal
         };
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
index 71510816d0b..84436de9aa3 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
+++ b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
@@ -14,11 +14,11 @@ LL |     stack!("overflow");
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `stack! { "overflow" }`
-   = note: to `print! (stack! ("overflow"));`
+   = note: to `print! (stack! ("overflow"))`
    = note: expanding `print! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
    = note: expanding `stack! { "overflow" }`
-   = note: to `print! (stack! ("overflow"));`
+   = note: to `print! (stack! ("overflow"))`
    = note: expanding `print! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
 
@@ -31,7 +31,7 @@ LL |     stack!("overflow");
    = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might be missing a string literal to format with
    |
-LL |             print!("{}", stack!($overflow));
+LL |             print!("{}", stack!($overflow))
    |                    +++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.rs b/tests/ui/infinite/issue-41731-infinite-macro-println.rs
index 491f18dc4c6..cf59afb0194 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-println.rs
+++ b/tests/ui/infinite/issue-41731-infinite-macro-println.rs
@@ -5,7 +5,7 @@
 fn main() {
     macro_rules! stack {
         ($overflow:expr) => {
-            println!(stack!($overflow));
+            println!(stack!($overflow))
             //~^ ERROR recursion limit reached while expanding
             //~| ERROR format argument must be a string literal
         };
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
index 645176d45cb..6d0432abe4c 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
+++ b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
@@ -14,11 +14,11 @@ LL |     stack!("overflow");
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `stack! { "overflow" }`
-   = note: to `println! (stack! ("overflow"));`
+   = note: to `println! (stack! ("overflow"))`
    = note: expanding `println! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
    = note: expanding `stack! { "overflow" }`
-   = note: to `println! (stack! ("overflow"));`
+   = note: to `println! (stack! ("overflow"))`
    = note: expanding `println! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
 
@@ -31,7 +31,7 @@ LL |     stack!("overflow");
    = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might be missing a string literal to format with
    |
-LL |             println!("{}", stack!($overflow));
+LL |             println!("{}", stack!($overflow))
    |                      +++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs
index 47348b0a0dd..d367dd5b299 100644
--- a/tests/ui/trait-bounds/more_maybe_bounds.rs
+++ b/tests/ui/trait-bounds/more_maybe_bounds.rs
@@ -1,7 +1,7 @@
 // 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.
+// there are places like supertrait bounds, trait object types or associated type bounds (ATB)
+// where we currently don't perform this check.
 #![feature(auto_traits, more_maybe_bounds, negative_impls)]
 
 trait Trait1 {}
@@ -13,11 +13,15 @@ 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`
 
+// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
+fn baz<T>() where T: Iterator<Item: ?Trait1> {}
+
 struct S;
 impl !Trait2 for S {}
 impl Trait1 for S {}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr
index 09c9fc31165..8dd83fc7728 100644
--- a/tests/ui/trait-bounds/more_maybe_bounds.stderr
+++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr
@@ -1,17 +1,17 @@
 error: bound modifier `?` can only be applied to default traits like `Sized`
-  --> $DIR/more_maybe_bounds.rs:16:20
+  --> $DIR/more_maybe_bounds.rs:17: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
+  --> $DIR/more_maybe_bounds.rs:17: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
+  --> $DIR/more_maybe_bounds.rs:17:40
    |
 LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
    |                                        ^^^^^^^
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
index b8eda1e7786..4c1f242a01c 100644
--- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
@@ -22,6 +22,10 @@ impl<T> S1<T> {
     fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
 }
 
+// Test associated type bounds (ATB).
+// issue: <https://github.com/rust-lang/rust/issues/135229>
+struct S6<T>(T) where T: Iterator<Item: ?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:
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
index 30285d62693..d3f0535e2f0 100644
--- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
@@ -38,8 +38,16 @@ LL |     fn f() where T: ?Sized {}
    |
    = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
 
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:27:41
+   |
+LL | struct S6<T>(T) where T: Iterator<Item: ?Sized>;
+   |                                         ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
 error: relaxed bounds are not permitted in supertrait bounds
-  --> $DIR/relaxed-bounds-invalid-places.rs:25:11
+  --> $DIR/relaxed-bounds-invalid-places.rs:29:11
    |
 LL | trait Tr: ?Sized {}
    |           ^^^^^^
@@ -47,19 +55,19 @@ LL | trait Tr: ?Sized {}
    = note: traits are `?Sized` by default
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:29:20
+  --> $DIR/relaxed-bounds-invalid-places.rs:33:20
    |
 LL | type O1 = dyn Tr + ?Sized;
    |                    ^^^^^^
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:30:15
+  --> $DIR/relaxed-bounds-invalid-places.rs:34:15
    |
 LL | type O2 = dyn ?Sized + ?Sized + Tr;
    |               ^^^^^^
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:30:24
+  --> $DIR/relaxed-bounds-invalid-places.rs:34:24
    |
 LL | type O2 = dyn ?Sized + ?Sized + Tr;
    |                        ^^^^^^
@@ -76,5 +84,5 @@ error: bound modifier `?` can only be applied to `Sized`
 LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
    |                                 ^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors