about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs54
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs7
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/check.rs36
-rw-r--r--compiler/rustc_query_system/src/query/job.rs15
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs4
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs35
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs78
-rw-r--r--library/alloc/src/collections/linked_list.rs5
-rw-r--r--library/core/src/array/mod.rs7
-rw-r--r--library/core/src/fmt/mod.rs29
-rw-r--r--library/core/src/num/int_macros.rs167
-rw-r--r--library/core/src/num/uint_macros.rs104
-rw-r--r--library/core/src/option.rs7
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/int_macros.rs49
-rw-r--r--library/core/tests/num/uint_macros.rs25
-rw-r--r--library/std/src/os/unix/fs.rs3
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs17
-rw-r--r--src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr15
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed25
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs24
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr37
-rw-r--r--src/test/ui/const-generics/const_trait_fn-issue-88433.rs26
-rw-r--r--src/test/ui/issues/issue-83190.rs49
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-2018.rs5
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-2018.stderr28
-rw-r--r--src/test/ui/iterators/into-iter-on-arrays-lint.stderr80
28 files changed, 726 insertions, 216 deletions
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 21fad5f9af6..5ac42c50c72 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                 _ => return,
             };
 
-            // As this is a method call expression, we have at least one
-            // argument.
+            // As this is a method call expression, we have at least one argument.
             let receiver_arg = &args[0];
+            let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
+            let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
 
-            // Peel all `Box<_>` layers. We have to special case `Box` here as
-            // `Box` is the only thing that values can be moved out of via
-            // method call. `Box::new([1]).into_iter()` should trigger this
-            // lint.
-            let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
-            let mut num_box_derefs = 0;
-            while recv_ty.is_box() {
-                num_box_derefs += 1;
-                recv_ty = recv_ty.boxed_ty();
-            }
+            let target = match adjustments.last() {
+                Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
+                _ => return,
+            };
 
-            // Make sure we found an array after peeling the boxes.
-            if !matches!(recv_ty.kind(), ty::Array(..)) {
-                return;
+            let types =
+                std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
+
+            let mut found_array = false;
+
+            for ty in types {
+                match ty.kind() {
+                    // If we run into a &[T; N] or &[T] first, there's nothing to warn about.
+                    // It'll resolve to the reference version.
+                    ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
+                    ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
+                    // Found an actual array type without matching a &[T; N] first.
+                    // This is the problematic case.
+                    ty::Array(..) => {
+                        found_array = true;
+                        break;
+                    }
+                    _ => {}
+                }
             }
 
-            // Make sure that there is an autoref coercion at the expected
-            // position. The first `num_box_derefs` adjustments are the derefs
-            // of the box.
-            match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
-                Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
-                _ => return,
+            if !found_array {
+                return;
             }
 
             // Emit lint diagnostic.
-            let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() {
+            let target = match *target.kind() {
                 ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
                 ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
-
                 // We know the original first argument type is an array type,
                 // we know that the first adjustment was an autoref coercion
                 // and we know that `IntoIterator` is the trait involved. The
@@ -135,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                         String::new(),
                         Applicability::MaybeIncorrect,
                     );
-                } else {
+                } else if receiver_ty.is_array() {
                     diag.multipart_suggestion(
                         "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
                         vec![
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 346a9e80217..83f6e79d5fc 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -411,8 +411,7 @@ impl<'tcx> Body<'tcx> {
     /// Returns an iterator over all function arguments.
     #[inline]
     pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
-        let arg_count = self.arg_count;
-        (1..arg_count + 1).map(Local::new)
+        (1..self.arg_count + 1).map(Local::new)
     }
 
     /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
@@ -421,9 +420,7 @@ impl<'tcx> Body<'tcx> {
     pub fn vars_and_temps_iter(
         &self,
     ) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
-        let arg_count = self.arg_count;
-        let local_count = self.local_decls.len();
-        (arg_count + 1..local_count).map(Local::new)
+        (self.arg_count + 1..self.local_decls.len()).map(Local::new)
     }
 
     #[inline]
diff --git a/compiler/rustc_mir/src/transform/check_consts/check.rs b/compiler/rustc_mir/src/transform/check_consts/check.rs
index 2b748062cdf..0c381276823 100644
--- a/compiler/rustc_mir/src/transform/check_consts/check.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/check.rs
@@ -9,7 +9,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
 use rustc_span::{sym, Span, Symbol};
@@ -793,7 +793,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
 
                 let fn_ty = func.ty(body, tcx);
 
-                let (mut callee, substs) = match *fn_ty.kind() {
+                let (mut callee, mut substs) = match *fn_ty.kind() {
                     ty::FnDef(def_id, substs) => (def_id, substs),
 
                     ty::FnPtr(_) => {
@@ -846,29 +846,31 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
                                 .iter()
                                 .find(|did| tcx.item_name(**did) == callee_name)
                             {
+                                // using internal substs is ok here, since this is only
+                                // used for the `resolve` call below
+                                substs = InternalSubsts::identity_for_item(tcx, did);
                                 callee = did;
                             }
                         }
-                        _ => {
-                            if !tcx.is_const_fn_raw(callee) {
-                                // At this point, it is only legal when the caller is marked with
-                                // #[default_method_body_is_const], and the callee is in the same
-                                // trait.
-                                let callee_trait = tcx.trait_of_item(callee);
-                                if callee_trait.is_some() {
-                                    if tcx.has_attr(caller, sym::default_method_body_is_const) {
-                                        if tcx.trait_of_item(caller) == callee_trait {
-                                            nonconst_call_permission = true;
-                                        }
+                        _ if !tcx.is_const_fn_raw(callee) => {
+                            // At this point, it is only legal when the caller is marked with
+                            // #[default_method_body_is_const], and the callee is in the same
+                            // trait.
+                            let callee_trait = tcx.trait_of_item(callee);
+                            if callee_trait.is_some() {
+                                if tcx.has_attr(caller, sym::default_method_body_is_const) {
+                                    if tcx.trait_of_item(caller) == callee_trait {
+                                        nonconst_call_permission = true;
                                     }
                                 }
+                            }
 
-                                if !nonconst_call_permission {
-                                    self.check_op(ops::FnCallNonConst);
-                                    return;
-                                }
+                            if !nonconst_call_permission {
+                                self.check_op(ops::FnCallNonConst);
+                                return;
                             }
                         }
+                        _ => {}
                     }
 
                     // Resolve a trait method call to its concrete implementation, which may be in a
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 63a8f062475..c3fdf4fc228 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -61,7 +61,7 @@ where
     }
 
     fn query(self, map: &QueryMap<D>) -> QueryStackFrame {
-        map.get(&self).unwrap().info.query.clone()
+        map.get(&self).unwrap().query.clone()
     }
 
     #[cfg(parallel_compiler)]
@@ -81,7 +81,7 @@ where
 }
 
 pub struct QueryJobInfo<D> {
-    pub info: QueryInfo,
+    pub query: QueryStackFrame,
     pub job: QueryJob<D>,
 }
 
@@ -155,7 +155,7 @@ where
 
         while let Some(job) = current_job {
             let info = query_map.get(&job).unwrap();
-            cycle.push(info.info.clone());
+            cycle.push(QueryInfo { span: info.job.span, query: info.query.clone() });
 
             if job == *self {
                 cycle.reverse();
@@ -170,7 +170,7 @@ where
                     .job
                     .parent
                     .as_ref()
-                    .map(|parent| (info.info.span, parent.query(&query_map)));
+                    .map(|parent| (info.job.span, parent.query(&query_map)));
                 return CycleError { usage, cycle };
             }
 
@@ -649,13 +649,10 @@ pub fn print_query_stack<CTX: QueryContext>(
         };
         let mut diag = Diagnostic::new(
             Level::FailureNote,
-            &format!(
-                "#{} [{}] {}",
-                i, query_info.info.query.name, query_info.info.query.description
-            ),
+            &format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
         );
         diag.span =
-            tcx.dep_context().sess().source_map().guess_head_span(query_info.info.span).into();
+            tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
         handler.force_print_diagnostic(diag);
 
         current_query = query_info.job.parent;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index a7511846cad..3f22de6fba4 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -130,8 +130,8 @@ where
             for (k, v) in shard.active.iter() {
                 if let QueryResult::Started(ref job) = *v {
                     let id = QueryJobId::new(job.id, shard_id, kind);
-                    let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
-                    jobs.insert(id, QueryJobInfo { info, job: job.clone() });
+                    let query = make_query(tcx, k.clone());
+                    jobs.insert(id, QueryJobInfo { query, job: job.clone() });
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index a25d0f80644..702f69a9fcf 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -47,7 +47,7 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint;
 use rustc_span::sym;
-use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 
 use rustc_data_structures::stable_map::FxHashMap;
@@ -680,15 +680,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         migrated_variables_concat
                     );
 
-                    // If the body was entirely expanded from a macro
-                    // invocation, i.e. the body is not contained inside the
-                    // closure span, then we walk up the expansion until we
-                    // find the span before the expansion.
-                    let closure_body_span = self.tcx.hir().span(body_id.hir_id)
-                        .find_ancestor_inside(closure_span)
-                        .unwrap_or(DUMMY_SP);
+                    let mut closure_body_span = {
+                        // If the body was entirely expanded from a macro
+                        // invocation, i.e. the body is not contained inside the
+                        // closure span, then we walk up the expansion until we
+                        // find the span before the expansion.
+                        let s = self.tcx.hir().span(body_id.hir_id);
+                        s.find_ancestor_inside(closure_span).unwrap_or(s)
+                    };
+
+                    if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
+                        if s.starts_with('$') {
+                            // Looks like a macro fragment. Try to find the real block.
+                            if let Some(hir::Node::Expr(&hir::Expr {
+                                kind: hir::ExprKind::Block(block, ..), ..
+                            })) = self.tcx.hir().find(body_id.hir_id) {
+                                // If the body is a block (with `{..}`), we use the span of that block.
+                                // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`.
+                                // Since we know it's a block, we know we can insert the `let _ = ..` without
+                                // breaking the macro syntax.
+                                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) {
+                                    closure_body_span = block.span;
+                                    s = snippet;
+                                }
+                            }
+                        }
 
-                    if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
                         let mut lines = s.lines();
                         let line1 = lines.next().unwrap_or_default();
 
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 3d483e322a8..ba70006fe96 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -21,29 +21,26 @@ use std::iter;
 
 use crate::mem_categorization as mc;
 
-///////////////////////////////////////////////////////////////////////////
-// The Delegate trait
-
 /// This trait defines the callbacks you can expect to receive when
 /// employing the ExprUseVisitor.
 pub trait Delegate<'tcx> {
-    // The value found at `place` is moved, depending
-    // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
-    //
-    // Use of a `Copy` type in a ByValue context is considered a use
-    // by `ImmBorrow` and `borrow` is called instead. This is because
-    // a shared borrow is the "minimum access" that would be needed
-    // to perform a copy.
-    //
-    //
-    // The parameter `diag_expr_id` indicates the HIR id that ought to be used for
-    // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
-    // id will be the id of the expression `expr` but the place itself will have
-    // the id of the binding in the pattern `pat`.
+    /// The value found at `place` is moved, depending
+    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
+    ///
+    /// Use of a `Copy` type in a ByValue context is considered a use
+    /// by `ImmBorrow` and `borrow` is called instead. This is because
+    /// a shared borrow is the "minimum access" that would be needed
+    /// to perform a copy.
+    ///
+    ///
+    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
+    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
+    /// id will be the id of the expression `expr` but the place itself will have
+    /// the id of the binding in the pattern `pat`.
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
 
-    // The value found at `place` is being borrowed with kind `bk`.
-    // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
+    /// The value found at `place` is being borrowed with kind `bk`.
+    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
     fn borrow(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -51,44 +48,47 @@ pub trait Delegate<'tcx> {
         bk: ty::BorrowKind,
     );
 
-    // The path at `assignee_place` is being assigned to.
-    // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
+    /// The path at `assignee_place` is being assigned to.
+    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
 
-    // The `place` should be a fake read because of specified `cause`.
+    /// The `place` should be a fake read because of specified `cause`.
     fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 enum ConsumeMode {
-    Copy, // reference to x where x has a type that copies
-    Move, // reference to x where x has a type that moves
+    /// reference to x where x has a type that copies
+    Copy,
+    /// reference to x where x has a type that moves
+    Move,
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum MutateMode {
     Init,
-    JustWrite,    // x = y
-    WriteAndRead, // x += y
+    /// Example: `x = y`
+    JustWrite,
+    /// Example: `x += y`
+    WriteAndRead,
 }
 
-///////////////////////////////////////////////////////////////////////////
-// The ExprUseVisitor type
-//
-// This is the code that actually walks the tree.
+/// The ExprUseVisitor type
+///
+/// This is the code that actually walks the tree.
 pub struct ExprUseVisitor<'a, 'tcx> {
     mc: mc::MemCategorizationContext<'a, 'tcx>,
     body_owner: LocalDefId,
     delegate: &'a mut dyn Delegate<'tcx>,
 }
 
-// If the MC results in an error, it's because the type check
-// failed (or will fail, when the error is uncovered and reported
-// during writeback). In this case, we just ignore this part of the
-// code.
-//
-// Note that this macro appears similar to try!(), but, unlike try!(),
-// it does not propagate the error.
+/// If the MC results in an error, it's because the type check
+/// failed (or will fail, when the error is uncovered and reported
+/// during writeback). In this case, we just ignore this part of the
+/// code.
+///
+/// Note that this macro appears similar to try!(), but, unlike try!(),
+/// it does not propagate the error.
 macro_rules! return_if_err {
     ($inp: expr) => {
         match $inp {
@@ -537,9 +537,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         self.walk_expr(with_expr);
     }
 
-    // Invoke the appropriate delegate calls for anything that gets
-    // consumed or borrowed as part of the automatic adjustment
-    // process.
+    /// Invoke the appropriate delegate calls for anything that gets
+    /// consumed or borrowed as part of the automatic adjustment
+    /// process.
     fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
         let adjustments = self.mc.typeck_results.expr_adjustments(expr);
         let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 7aa24ff4afa..9d45c5082db 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -300,7 +300,10 @@ impl<T> LinkedList<T> {
         let tail = self.tail.take();
         let len = mem::replace(&mut self.len, 0);
         if let Some(head) = head {
-            let tail = tail.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() });
+            // SAFETY: In a LinkedList, either both the head and tail are None because
+            // the list is empty, or both head and tail are Some because the list is populated.
+            // Since we have verified the head is Some, we are sure the tail is Some too.
+            let tail = unsafe { tail.unwrap_unchecked() };
             Some((head, tail, len))
         } else {
             None
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 3c638e655dc..70cccd31b92 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -459,11 +459,8 @@ where
     debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
     debug_assert!(N <= iter.size_hint().0);
 
-    match collect_into_array(iter) {
-        Some(array) => array,
-        // SAFETY: covered by the function contract.
-        None => unsafe { crate::hint::unreachable_unchecked() },
-    }
+    // SAFETY: covered by the function contract.
+    unsafe { collect_into_array(iter).unwrap_unchecked() }
 }
 
 /// Pulls `N` items from `iter` and returns them as an array. If the iterator
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 1d75ac3d254..aff789f2afa 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -402,7 +402,7 @@ impl<'a> Arguments<'a> {
 
         if self.args.is_empty() {
             pieces_length
-        } else if self.pieces[0] == "" && pieces_length < 16 {
+        } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 {
             // If the format string starts with an argument,
             // don't preallocate anything, unless length
             // of pieces is significant.
@@ -1163,7 +1163,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
                 }
                 // SAFETY: arg and args.args come from the same Arguments,
                 // which guarantees the indexes are always within bounds.
-                unsafe { run(&mut formatter, arg, &args.args) }?;
+                unsafe { run(&mut formatter, arg, args.args) }?;
                 idx += 1;
             }
         }
@@ -1409,7 +1409,7 @@ impl<'a> Formatter<'a> {
                 // we know that it can't panic. Use `get` + `unwrap_or` to avoid
                 // `unsafe` and otherwise don't emit any panic-related code
                 // here.
-                s.get(..i).unwrap_or(&s)
+                s.get(..i).unwrap_or(s)
             } else {
                 &s
             }
@@ -1421,16 +1421,21 @@ impl<'a> Formatter<'a> {
             // If we're under the maximum length, and there's no minimum length
             // requirements, then we can just emit the string
             None => self.buf.write_str(s),
-            // If we're under the maximum width, check if we're over the minimum
-            // width, if so it's as easy as just emitting the string.
-            Some(width) if s.chars().count() >= width => self.buf.write_str(s),
-            // If we're under both the maximum and the minimum width, then fill
-            // up the minimum width with the specified string + some alignment.
             Some(width) => {
-                let align = rt::v1::Alignment::Left;
-                let post_padding = self.padding(width - s.chars().count(), align)?;
-                self.buf.write_str(s)?;
-                post_padding.write(self.buf)
+                let chars_count = s.chars().count();
+                // If we're under the maximum width, check if we're over the minimum
+                // width, if so it's as easy as just emitting the string.
+                if chars_count >= width {
+                    self.buf.write_str(s)
+                }
+                // If we're under both the maximum and the minimum width, then fill
+                // up the minimum width with the specified string + some alignment.
+                else {
+                    let align = rt::v1::Alignment::Left;
+                    let post_padding = self.padding(width - chars_count, align)?;
+                    self.buf.write_str(s)?;
+                    post_padding.write(self.buf)
+                }
             }
         }
     }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 1a310917fdf..780d6c34c91 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1834,6 +1834,173 @@ macro_rules! int_impl {
             }
         }
 
+        /// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
+        /// let b = 3;
+        ///
+        /// assert_eq!(a.div_floor(b), 2);
+        /// assert_eq!(a.div_floor(-b), -3);
+        /// assert_eq!((-a).div_floor(b), -3);
+        /// assert_eq!((-a).div_floor(-b), 2);
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_floor(self, rhs: Self) -> Self {
+            let d = self / rhs;
+            let r = self % rhs;
+            if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
+                d - 1
+            } else {
+                d
+            }
+        }
+
+        /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the division results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
+        /// let b = 3;
+        ///
+        /// assert_eq!(a.div_ceil(b), 3);
+        /// assert_eq!(a.div_ceil(-b), -2);
+        /// assert_eq!((-a).div_ceil(b), -2);
+        /// assert_eq!((-a).div_ceil(-b), 3);
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_ceil(self, rhs: Self) -> Self {
+            let d = self / rhs;
+            let r = self % rhs;
+            if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
+                d + 1
+            } else {
+                d
+            }
+        }
+
+        /// If `rhs` is positive, calculates the smallest value greater than or
+        /// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
+        /// calculates the largest value less than or equal to `self` that is a
+        /// multiple of `rhs`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the operation results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
+        #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
+        #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
+        #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")]
+        #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn next_multiple_of(self, rhs: Self) -> Self {
+            // This would otherwise fail when calculating `r` when self == T::MIN.
+            if rhs == -1 {
+                return self;
+            }
+
+            let r = self % rhs;
+            let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
+                r + rhs
+            } else {
+                r
+            };
+
+            if m == 0 {
+                self
+            } else {
+                self + (rhs - m)
+            }
+        }
+
+        /// If `rhs` is positive, calculates the smallest value greater than or
+        /// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
+        /// calculates the largest value less than or equal to `self` that is a
+        /// multiple of `rhs`. Returns `None` if `rhs` is zero or the operation
+        /// would result in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
+        #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
+        #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
+        #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-16));")]
+        #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-24));")]
+        #[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
+            // This would otherwise fail when calculating `r` when self == T::MIN.
+            if rhs == -1 {
+                return Some(self);
+            }
+
+            let r = try_opt!(self.checked_rem(rhs));
+            let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
+                try_opt!(r.checked_add(rhs))
+            } else {
+                r
+            };
+
+            if m == 0 {
+                Some(self)
+            } else {
+                self.checked_add(try_opt!(rhs.checked_sub(m)))
+            }
+        }
+
         /// Returns the logarithm of the number with respect to an arbitrary base.
         ///
         /// This method might not be optimized owing to implementation details;
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 9366efb32bc..02a5ed4ca80 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1848,6 +1848,110 @@ macro_rules! uint_impl {
             self % rhs
         }
 
+        /// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
+        ///
+        /// This is the same as performing `self / rhs` for all unsigned integers.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[inline(always)]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_floor(self, rhs: Self) -> Self {
+            self / rhs
+        }
+
+        /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn div_ceil(self, rhs: Self) -> Self {
+            let d = self / rhs;
+            let r = self % rhs;
+            if r > 0 && rhs > 0 {
+                d + 1
+            } else {
+                d
+            }
+        }
+
+        /// Calculates the smallest value greater than or equal to `self` that
+        /// is a multiple of `rhs`.
+        ///
+        /// # Panics
+        ///
+        /// This function will panic if `rhs` is 0 or the operation results in overflow.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn next_multiple_of(self, rhs: Self) -> Self {
+            match self % rhs {
+                0 => self,
+                r => self + (rhs - r)
+            }
+        }
+
+        /// Calculates the smallest value greater than or equal to `self` that
+        /// is a multiple of `rhs`. If `rhs` is negative,
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(int_roundings)]
+        #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
+        #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
+        #[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
+        /// ```
+        #[unstable(feature = "int_roundings", issue = "88581")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[rustc_inherit_overflow_checks]
+        pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
+            match try_opt!(self.checked_rem(rhs)) {
+                0 => Some(self),
+                r => self.checked_add(try_opt!(rhs.checked_sub(r)))
+            }
+        }
+
         /// Returns `true` if and only if `self == 2^k` for some `k`.
         ///
         /// # Examples
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 47865240f6a..9d5e03dd0de 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1198,11 +1198,8 @@ impl<T> Option<T> {
     pub fn insert(&mut self, value: T) -> &mut T {
         *self = Some(value);
 
-        match self {
-            Some(v) => v,
-            // SAFETY: the code above just filled the option
-            None => unsafe { hint::unreachable_unchecked() },
-        }
+        // SAFETY: the code above just filled the option
+        unsafe { self.as_mut().unwrap_unchecked() }
     }
 
     /// Inserts `value` into the option if it is [`None`], then
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 7853b571be3..19bcc45108d 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -64,6 +64,7 @@
 #![feature(unsized_tuple_coercion)]
 #![feature(const_option)]
 #![feature(integer_atomics)]
+#![feature(int_roundings)]
 #![feature(slice_group_by)]
 #![feature(trusted_random_access)]
 #![feature(unsize)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 90c47656784..d2d655ea2c7 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -289,6 +289,55 @@ macro_rules! int_module {
                 assert_eq!(r.saturating_pow(3), -8 as $T);
                 assert_eq!(r.saturating_pow(0), 1 as $T);
             }
+
+            #[test]
+            fn test_div_floor() {
+                let a: $T = 8;
+                let b = 3;
+                assert_eq!(a.div_floor(b), 2);
+                assert_eq!(a.div_floor(-b), -3);
+                assert_eq!((-a).div_floor(b), -3);
+                assert_eq!((-a).div_floor(-b), 2);
+            }
+
+            #[test]
+            fn test_div_ceil() {
+                let a: $T = 8;
+                let b = 3;
+                assert_eq!(a.div_ceil(b), 3);
+                assert_eq!(a.div_ceil(-b), -2);
+                assert_eq!((-a).div_ceil(b), -2);
+                assert_eq!((-a).div_ceil(-b), 3);
+            }
+
+            #[test]
+            fn test_next_multiple_of() {
+                assert_eq!((16 as $T).next_multiple_of(8), 16);
+                assert_eq!((23 as $T).next_multiple_of(8), 24);
+                assert_eq!((16 as $T).next_multiple_of(-8), 16);
+                assert_eq!((23 as $T).next_multiple_of(-8), 16);
+                assert_eq!((-16 as $T).next_multiple_of(8), -16);
+                assert_eq!((-23 as $T).next_multiple_of(8), -16);
+                assert_eq!((-16 as $T).next_multiple_of(-8), -16);
+                assert_eq!((-23 as $T).next_multiple_of(-8), -24);
+                assert_eq!(MIN.next_multiple_of(-1), MIN);
+            }
+
+            #[test]
+            fn test_checked_next_multiple_of() {
+                assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
+                assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
+                assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16));
+                assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16));
+                assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16));
+                assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16));
+                assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
+                assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
+                assert_eq!((1 as $T).checked_next_multiple_of(0), None);
+                assert_eq!(MAX.checked_next_multiple_of(2), None);
+                assert_eq!(MIN.checked_next_multiple_of(-3), None);
+                assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
+            }
         }
     };
 }
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index 445f8fb350e..49f8f1f13fa 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -205,6 +205,31 @@ macro_rules! uint_module {
                 assert_eq!(r.overflowing_pow(2), (1 as $T, true));
                 assert_eq!(r.saturating_pow(2), MAX);
             }
+
+            #[test]
+            fn test_div_floor() {
+                assert_eq!((8 as $T).div_floor(3), 2);
+            }
+
+            #[test]
+            fn test_div_ceil() {
+                assert_eq!((8 as $T).div_ceil(3), 3);
+            }
+
+            #[test]
+            fn test_next_multiple_of() {
+                assert_eq!((16 as $T).next_multiple_of(8), 16);
+                assert_eq!((23 as $T).next_multiple_of(8), 24);
+                assert_eq!(MAX.next_multiple_of(1), MAX);
+            }
+
+            #[test]
+            fn test_checked_next_multiple_of() {
+                assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
+                assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
+                assert_eq!((1 as $T).checked_next_multiple_of(0), None);
+                assert_eq!(MAX.checked_next_multiple_of(2), None);
+            }
         }
     };
 }
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index e4ce788f741..6cf37f23c57 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -934,7 +934,6 @@ impl DirBuilderExt for fs::DirBuilder {
 /// # Examples
 ///
 /// ```no_run
-/// #![feature(unix_chroot)]
 /// use std::os::unix::fs;
 ///
 /// fn main() -> std::io::Result<()> {
@@ -944,7 +943,7 @@ impl DirBuilderExt for fs::DirBuilder {
 ///     Ok(())
 /// }
 /// ```
-#[unstable(feature = "unix_chroot", issue = "84715")]
+#[stable(feature = "unix_chroot", since = "1.56.0")]
 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
     sys::fs::chroot(dir.as_ref())
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bde821c5d9c..a9baa1c31ae 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1311,10 +1311,11 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
         }
         hir::QPath::TypeRelative(ref qself, ref segment) => {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-            let res = if let ty::Projection(proj) = ty.kind() {
-                Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id)
-            } else {
-                Res::Err
+            let res = match ty.kind() {
+                ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
+                // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
+                ty::Error(_) => return Type::Infer,
+                _ => bug!("clean: expected associated type, found `{:?}`", ty),
             };
             let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
             Type::QPath {
@@ -1379,6 +1380,7 @@ impl Clean<Type> for hir::Ty<'_> {
                 DynTrait(bounds, lifetime)
             }
             TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))),
+            // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
         }
diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
new file mode 100644
index 00000000000..3ad56aebc21
--- /dev/null
+++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
@@ -0,0 +1,17 @@
+// This test ensures that rustdoc does not panic on inherented associated types
+// that are referred to without fully-qualified syntax.
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+pub struct Struct;
+
+impl Struct {
+    pub type AssocTy = usize;
+    pub const AssocConst: Self::AssocTy = 42;
+    //~^ ERROR ambiguous associated type
+    //~| HELP use fully-qualified syntax
+    // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc
+    //~| ERROR ambiguous associated type
+    //~| HELP use fully-qualified syntax
+}
diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
new file mode 100644
index 00000000000..b963b722f66
--- /dev/null
+++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
@@ -0,0 +1,15 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
+   |
+LL |     pub const AssocConst: Self::AssocTy = 42;
+   |                           ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
+
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
+   |
+LL |     pub const AssocConst: Self::AssocTy = 42;
+   |                           ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
new file mode 100644
index 00000000000..f91454aa211
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_compatibility)]
+
+macro_rules! m {
+    (@ $body:expr) => {{
+        let f = || $body;
+        //~^ WARNING: drop order
+        f();
+    }};
+    ($body:block) => {{
+        m!(@ $body);
+    }};
+}
+
+fn main() {
+    let a = (1.to_string(), 2.to_string());
+    m!({
+        let _ = &a;
+        //~^ HELP: add a dummy
+        let x = a.0;
+        println!("{}", x);
+    });
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
new file mode 100644
index 00000000000..5a1026d0433
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_compatibility)]
+
+macro_rules! m {
+    (@ $body:expr) => {{
+        let f = || $body;
+        //~^ WARNING: drop order
+        f();
+    }};
+    ($body:block) => {{
+        m!(@ $body);
+    }};
+}
+
+fn main() {
+    let a = (1.to_string(), 2.to_string());
+    m!({
+        //~^ HELP: add a dummy
+        let x = a.0;
+        println!("{}", x);
+    });
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
new file mode 100644
index 00000000000..e6e5598f6d2
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
@@ -0,0 +1,37 @@
+warning: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/closure-body-macro-fragment.rs:8:17
+   |
+LL |           let f = || $body;
+   |  _________________^
+LL | |
+LL | |         f();
+LL | |     }};
+   | |     - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
+LL | |     ($body:block) => {{
+LL | |         m!(@ $body);
+   | |__________________^
+...
+LL | /     m!({
+LL | |
+LL | |         let x = a.0;
+   | |                 --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
+LL | |         println!("{}", x);
+LL | |     });
+   | |_______- in this macro invocation
+   |
+note: the lint level is defined here
+  --> $DIR/closure-body-macro-fragment.rs:4:9
+   |
+LL | #![warn(rust_2021_compatibility)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]`
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+   = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a dummy let to cause `a` to be fully captured
+   |
+LL ~     m!({
+LL +         let _ = &a;
+   |
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/const-generics/const_trait_fn-issue-88433.rs b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs
new file mode 100644
index 00000000000..8724fa69825
--- /dev/null
+++ b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs
@@ -0,0 +1,26 @@
+// build-pass
+
+#![feature(const_trait_impl)]
+
+trait Func<T> {
+    type Output;
+
+    fn call_once(self, arg: T) -> Self::Output;
+}
+
+
+struct Closure;
+
+impl const Func<&usize> for Closure {
+    type Output = usize;
+
+    fn call_once(self, arg: &usize) -> Self::Output {
+        *arg
+    }
+}
+
+enum Bug<T = [(); Closure.call_once(&0) ]> {
+    V(T),
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-83190.rs b/src/test/ui/issues/issue-83190.rs
new file mode 100644
index 00000000000..da931c3edaf
--- /dev/null
+++ b/src/test/ui/issues/issue-83190.rs
@@ -0,0 +1,49 @@
+// check-pass
+
+// Regression test for issue #83190, triggering an ICE in borrowck.
+
+pub trait Any {}
+impl<T> Any for T {}
+
+pub trait StreamOnce {
+    type Range;
+}
+
+pub trait Parser<Input>: Sized {
+    type Output;
+    type PartialState;
+    fn map(self) -> Map<Self> {
+        todo!()
+    }
+}
+
+pub struct Map<P>(P);
+impl<I, P: Parser<I, Output = ()>> Parser<I> for Map<P> {
+    type Output = ();
+    type PartialState = P::PartialState;
+}
+
+struct TakeWhile1<Input>(Input);
+impl<I: StreamOnce> Parser<I> for TakeWhile1<I> {
+    type Output = I::Range;
+    type PartialState = ();
+}
+impl<I> TakeWhile1<I> {
+    fn new() -> Self {
+        todo!()
+    }
+}
+
+impl<I, A: Parser<I>> Parser<I> for (A,) {
+    type Output = ();
+    type PartialState = Map<A::Output>;
+}
+
+pub fn metric_stream_parser<'a, I>() -> impl Parser<I, Output = (), PartialState = impl Any + 'a>
+where
+    I: StreamOnce<Range = &'a [()]>,
+{
+    (TakeWhile1::new(),).map()
+}
+
+fn main() {}
diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.rs b/src/test/ui/iterators/into-iter-on-arrays-2018.rs
index e56c2956a69..60995170a51 100644
--- a/src/test/ui/iterators/into-iter-on-arrays-2018.rs
+++ b/src/test/ui/iterators/into-iter-on-arrays-2018.rs
@@ -19,9 +19,12 @@ fn main() {
     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
     //~| WARNING this changes meaning
 
-    // The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
     let _: Iter<'_, i32> = Rc::new(array).into_iter();
+    //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
     let _: Iter<'_, i32> = Array(array).into_iter();
+    //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
 
     // But you can always use the trait method explicitly as an array.
     let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);
diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr
index e9780d9b165..bc08fdcafa0 100644
--- a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr
+++ b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr
@@ -20,21 +20,31 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
   --> $DIR/into-iter-on-arrays-2018.rs:18:44
    |
 LL |     let _: Iter<'_, i32> = Box::new(array).into_iter();
-   |                                            ^^^^^^^^^
+   |                                            ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
+  --> $DIR/into-iter-on-arrays-2018.rs:22:43
    |
-LL |     let _: Iter<'_, i32> = Box::new(array).iter();
-   |                                            ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+LL |     let _: Iter<'_, i32> = Rc::new(array).into_iter();
+   |                                           ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
+
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
+  --> $DIR/into-iter-on-arrays-2018.rs:25:41
    |
-LL |     let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array));
-   |                            ++++++++++++++++++++++++               ~
+LL |     let _: Iter<'_, i32> = Array(array).into_iter();
+   |                                         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
-  --> $DIR/into-iter-on-arrays-2018.rs:29:24
+  --> $DIR/into-iter-on-arrays-2018.rs:32:24
    |
 LL |     for _ in [1, 2, 3].into_iter() {}
    |                        ^^^^^^^^^
@@ -51,5 +61,5 @@ LL -     for _ in [1, 2, 3].into_iter() {}
 LL +     for _ in [1, 2, 3] {}
    | 
 
-warning: 3 warnings emitted
+warning: 5 warnings emitted
 
diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr
index 138becc4ffe..2df1a06df20 100644
--- a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr
+++ b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -71,137 +71,73 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
   --> $DIR/into-iter-on-arrays-lint.rs:23:21
    |
 LL |     Box::new(small).into_iter();
-   |                     ^^^^^^^^^
+   |                     ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(small).iter();
-   |                     ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(small));
-   |     ++++++++++++++++++++++++               ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:26:22
    |
 LL |     Box::new([1, 2]).into_iter();
-   |                      ^^^^^^^^^
+   |                      ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new([1, 2]).iter();
-   |                      ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new([1, 2]));
-   |     ++++++++++++++++++++++++                ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:29:19
    |
 LL |     Box::new(big).into_iter();
-   |                   ^^^^^^^^^
+   |                   ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(big).iter();
-   |                   ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(big));
-   |     ++++++++++++++++++++++++             ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:32:25
    |
 LL |     Box::new([0u8; 33]).into_iter();
-   |                         ^^^^^^^^^
+   |                         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new([0u8; 33]).iter();
-   |                         ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new([0u8; 33]));
-   |     ++++++++++++++++++++++++                   ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:36:31
    |
 LL |     Box::new(Box::new(small)).into_iter();
-   |                               ^^^^^^^^^
+   |                               ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(Box::new(small)).iter();
-   |                               ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(Box::new(small)));
-   |     ++++++++++++++++++++++++                         ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:39:32
    |
 LL |     Box::new(Box::new([1, 2])).into_iter();
-   |                                ^^^^^^^^^
+   |                                ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(Box::new([1, 2])).iter();
-   |                                ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(Box::new([1, 2])));
-   |     ++++++++++++++++++++++++                          ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:42:29
    |
 LL |     Box::new(Box::new(big)).into_iter();
-   |                             ^^^^^^^^^
+   |                             ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(Box::new(big)).iter();
-   |                             ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(Box::new(big)));
-   |     ++++++++++++++++++++++++                       ~
 
 warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
   --> $DIR/into-iter-on-arrays-lint.rs:45:35
    |
 LL |     Box::new(Box::new([0u8; 33])).into_iter();
-   |                                   ^^^^^^^^^
+   |                                   ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
-   |
-LL |     Box::new(Box::new([0u8; 33])).iter();
-   |                                   ~~~~
-help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
-   |
-LL |     IntoIterator::into_iter(Box::new(Box::new([0u8; 33])));
-   |     ++++++++++++++++++++++++                             ~
 
 warning: 12 warnings emitted