about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--compiler/rustc_ast/src/ast.rs13
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/util/classify.rs14
-rw-r--r--compiler/rustc_ast/src/visit.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs125
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs19
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs24
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs8
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs21
-rw-r--r--compiler/rustc_lint/src/unused.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs4
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs21
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs3
-rw-r--r--compiler/rustc_pattern_analysis/src/lints.rs22
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs21
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs20
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs27
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--library/core/src/async_iter/async_iter.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs1
-rw-r--r--src/ci/github-actions/ci.yml5
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md266
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs19
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/rustfmt/src/closures.rs4
-rw-r--r--src/tools/rustfmt/src/expr.rs24
-rw-r--r--src/tools/rustfmt/src/matches.rs2
-rw-r--r--src/tools/rustfmt/src/overflow.rs2
-rw-r--r--src/tools/rustfmt/src/utils.rs4
-rw-r--r--tests/codegen/overaligned-constant.rs2
-rw-r--r--tests/ui/async-await/feature-async-for-loop.rs23
-rw-r--r--tests/ui/async-await/feature-async-for-loop.stderr21
-rw-r--r--tests/ui/async-await/for-await-2015.rs10
-rw-r--r--tests/ui/async-await/for-await-consumes-iter.rs20
-rw-r--r--tests/ui/async-await/for-await-consumes-iter.stderr27
-rw-r--r--tests/ui/async-await/for-await-passthrough.rs32
-rw-r--r--tests/ui/async-await/for-await.rs24
-rw-r--r--tests/ui/entry-point/return-ty-has-bound-vars.rs3
-rw-r--r--tests/ui/entry-point/return-ty-has-bound-vars.stderr9
-rw-r--r--tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr4
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.rs146
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.stderr101
64 files changed, 1015 insertions, 184 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4cf603519b1..540e1eb157e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -289,8 +289,9 @@ jobs:
             os: ubuntu-20.04-4core-16gb
             env: {}
           - name: x86_64-gnu-integration
+            env:
+              CI_ONLY_WHEN_CHANNEL: nightly
             os: ubuntu-20.04-16core-64gb
-            env: {}
           - name: x86_64-gnu-debug
             os: ubuntu-20.04-8core-32gb
             env: {}
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3d59c034210..929757fced8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1249,7 +1249,7 @@ impl Expr {
             ExprKind::Let(..) => ExprPrecedence::Let,
             ExprKind::If(..) => ExprPrecedence::If,
             ExprKind::While(..) => ExprPrecedence::While,
-            ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
+            ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
             ExprKind::Loop(..) => ExprPrecedence::Loop,
             ExprKind::Match(..) => ExprPrecedence::Match,
             ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1411,10 +1411,10 @@ pub enum ExprKind {
     While(P<Expr>, P<Block>, Option<Label>),
     /// A `for` loop, with an optional label.
     ///
-    /// `'label: for pat in expr { block }`
+    /// `'label: for await? pat in iter { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
+    ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
     /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
     ///
     /// `'label: loop { block }`
@@ -1517,6 +1517,13 @@ pub enum ExprKind {
     Err,
 }
 
+/// Used to differentiate between `for` loops and `for await` loops.
+#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum ForLoopKind {
+    For,
+    ForAwait,
+}
+
 /// Used to differentiate between `async {}` blocks and `gen {}` blocks.
 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
 pub enum GenBlockKind {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 557ae02a8f9..82f28143630 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1389,7 +1389,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_block(body);
             visit_opt(label, |label| vis.visit_label(label));
         }
-        ExprKind::ForLoop(pat, iter, body, label) => {
+        ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
             vis.visit_pat(pat);
             vis.visit_expr(iter);
             vis.visit_block(body);
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 4dece079783..65036bcdc36 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -19,7 +19,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
             | ast::ExprKind::Block(..)
             | ast::ExprKind::While(..)
             | ast::ExprKind::Loop(..)
-            | ast::ExprKind::ForLoop(..)
+            | ast::ExprKind::ForLoop { .. }
             | ast::ExprKind::TryBlock(..)
             | ast::ExprKind::ConstBlock(..)
     )
@@ -48,8 +48,16 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
             Closure(closure) => {
                 expr = &closure.body;
             }
-            Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
-            | TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
+            Gen(..)
+            | Block(..)
+            | ForLoop { .. }
+            | If(..)
+            | Loop(..)
+            | Match(..)
+            | Struct(..)
+            | TryBlock(..)
+            | While(..)
+            | ConstBlock(_) => break Some(expr),
 
             // FIXME: These can end in `}`, but changing these would break stable code.
             InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 27f1b84f372..45261ca48fc 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -844,11 +844,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
-        ExprKind::ForLoop(pattern, subexpression, block, opt_label) => {
-            walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_pat(pattern);
-            visitor.visit_expr(subexpression);
-            visitor.visit_block(block);
+        ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
+            walk_list!(visitor, visit_label, label);
+            visitor.visit_pat(pat);
+            visitor.visit_expr(iter);
+            visitor.visit_block(body);
         }
         ExprKind::Loop(block, opt_label, _) => {
             walk_list!(visitor, visit_label, opt_label);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 704f124dbcb..2d61f3bceec 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -56,12 +56,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     return ex;
                 }
                 // Desugar `ExprForLoop`
-                // from: `[opt_ident]: for <pat> in <head> <body>`
+                // from: `[opt_ident]: for await? <pat> in <iter> <body>`
                 //
                 // This also needs special handling because the HirId of the returned `hir::Expr` will not
                 // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
-                ExprKind::ForLoop(pat, head, body, opt_label) => {
-                    return self.lower_expr_for(e, pat, head, body, *opt_label);
+                ExprKind::ForLoop { pat, iter, body, label, kind } => {
+                    return self.lower_expr_for(e, pat, iter, body, *label, *kind);
                 }
                 _ => (),
             }
@@ -337,7 +337,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ),
                 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
 
-                ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
+                ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
                     unreachable!("already handled")
                 }
 
@@ -874,6 +874,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// }
     /// ```
     fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+        let expr = self.arena.alloc(self.lower_expr_mut(expr));
+        self.make_lowered_await(await_kw_span, expr, FutureKind::Future)
+    }
+
+    /// Takes an expr that has already been lowered and generates a desugared await loop around it
+    fn make_lowered_await(
+        &mut self,
+        await_kw_span: Span,
+        expr: &'hir hir::Expr<'hir>,
+        await_kind: FutureKind,
+    ) -> hir::ExprKind<'hir> {
         let full_span = expr.span.to(await_kw_span);
 
         let is_async_gen = match self.coroutine_kind {
@@ -887,13 +898,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
         };
 
-        let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
+        let features = match await_kind {
+            FutureKind::Future => None,
+            FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
+        };
+        let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
         let gen_future_span = self.mark_span_with_reason(
             DesugaringKind::Await,
             full_span,
             Some(self.allow_gen_future.clone()),
         );
-        let expr = self.lower_expr_mut(expr);
         let expr_hir_id = expr.hir_id;
 
         // Note that the name of this binding must not be changed to something else because
@@ -934,11 +948,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 hir::LangItem::GetContext,
                 arena_vec![self; task_context],
             );
-            let call = self.expr_call_lang_item_fn(
-                span,
-                hir::LangItem::FuturePoll,
-                arena_vec![self; new_unchecked, get_context],
-            );
+            let call = match await_kind {
+                FutureKind::Future => self.expr_call_lang_item_fn(
+                    span,
+                    hir::LangItem::FuturePoll,
+                    arena_vec![self; new_unchecked, get_context],
+                ),
+                FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
+                    span,
+                    hir::LangItem::AsyncIteratorPollNext,
+                    arena_vec![self; new_unchecked, get_context],
+                ),
+            };
             self.arena.alloc(self.expr_unsafe(call))
         };
 
@@ -1020,11 +1041,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let awaitee_arm = self.arm(awaitee_pat, loop_expr);
 
         // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
-        let into_future_expr = self.expr_call_lang_item_fn(
-            span,
-            hir::LangItem::IntoFutureIntoFuture,
-            arena_vec![self; expr],
-        );
+        let into_future_expr = match await_kind {
+            FutureKind::Future => self.expr_call_lang_item_fn(
+                span,
+                hir::LangItem::IntoFutureIntoFuture,
+                arena_vec![self; *expr],
+            ),
+            // Not needed for `for await` because we expect to have already called
+            // `IntoAsyncIterator::into_async_iter` on it.
+            FutureKind::AsyncIterator => expr,
+        };
 
         // match <into_future_expr> {
         //     mut __awaitee => loop { .. }
@@ -1685,6 +1711,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         head: &Expr,
         body: &Block,
         opt_label: Option<Label>,
+        loop_kind: ForLoopKind,
     ) -> hir::Expr<'hir> {
         let head = self.lower_expr_mut(head);
         let pat = self.lower_pat(pat);
@@ -1713,17 +1740,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let (iter_pat, iter_pat_nid) =
             self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
 
-        // `match Iterator::next(&mut iter) { ... }`
         let match_expr = {
             let iter = self.expr_ident(head_span, iter, iter_pat_nid);
-            let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
-            let next_expr = self.expr_call_lang_item_fn(
-                head_span,
-                hir::LangItem::IteratorNext,
-                arena_vec![self; ref_mut_iter],
-            );
+            let next_expr = match loop_kind {
+                ForLoopKind::For => {
+                    // `Iterator::next(&mut iter)`
+                    let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
+                    self.expr_call_lang_item_fn(
+                        head_span,
+                        hir::LangItem::IteratorNext,
+                        arena_vec![self; ref_mut_iter],
+                    )
+                }
+                ForLoopKind::ForAwait => {
+                    // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this
+                    // to make_lowered_await with `FutureKind::AsyncIterator` which will generator
+                    // calls to `poll_next`. In user code, this would probably be a call to
+                    // `Pin::as_mut` but here it's easy enough to do `new_unchecked`.
+
+                    // `&mut iter`
+                    let iter = self.expr_mut_addr_of(head_span, iter);
+                    // `Pin::new_unchecked(...)`
+                    let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
+                        head_span,
+                        hir::LangItem::PinNewUnchecked,
+                        arena_vec![self; iter],
+                    ));
+                    // `unsafe { ... }`
+                    let iter = self.arena.alloc(self.expr_unsafe(iter));
+                    let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
+                    self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
+                }
+            };
             let arms = arena_vec![self; none_arm, some_arm];
 
+            // `match $next_expr { ... }`
             self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
         };
         let match_stmt = self.stmt_expr(for_span, match_expr);
@@ -1743,13 +1794,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
 
-        // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
-        let into_iter_expr = {
-            self.expr_call_lang_item_fn(
-                head_span,
-                hir::LangItem::IntoIterIntoIter,
-                arena_vec![self; head],
-            )
+        let into_iter_expr = match loop_kind {
+            ForLoopKind::For => {
+                // `::std::iter::IntoIterator::into_iter(<head>)`
+                self.expr_call_lang_item_fn(
+                    head_span,
+                    hir::LangItem::IntoIterIntoIter,
+                    arena_vec![self; head],
+                )
+            }
+            ForLoopKind::ForAwait => self.arena.alloc(head),
         };
 
         let match_expr = self.arena.alloc(self.expr_match(
@@ -2152,3 +2206,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 }
+
+/// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
+/// of future we are awaiting.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum FutureKind {
+    /// We are awaiting a normal future
+    Future,
+    /// We are awaiting something that's known to be an AsyncIterator (i.e. we are in the header of
+    /// a `for await` loop)
+    AsyncIterator,
+}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ed033d86008..e35d7d62cad 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -130,6 +130,7 @@ struct LoweringContext<'a, 'hir> {
     allow_try_trait: Lrc<[Symbol]>,
     allow_gen_future: Lrc<[Symbol]>,
     allow_async_iterator: Lrc<[Symbol]>,
+    allow_for_await: Lrc<[Symbol]>,
 
     /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
     /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
@@ -174,6 +175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             } else {
                 [sym::gen_future].into()
             },
+            allow_for_await: [sym::async_iterator].into(),
             // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
             // interact with `gen`/`async gen` blocks
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1cc9309c45c..b20a0b9461f 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -527,6 +527,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         "async closures are unstable",
         "to use an async block, remove the `||`: `async {`"
     );
+    gate_all!(async_for_loop, "`for await` loops are experimental");
     gate_all!(
         closure_lifetime_binder,
         "`for<...>` binders for closures are experimental",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index f5ffcddb83d..f868beec812 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,5 +1,6 @@
 use crate::pp::Breaks::Inconsistent;
 use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use ast::ForLoopKind;
 use itertools::{Itertools, Position};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
@@ -418,20 +419,23 @@ impl<'a> State<'a> {
                 self.space();
                 self.print_block_with_attrs(blk, attrs);
             }
-            ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => {
-                if let Some(label) = opt_label {
+            ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
+                if let Some(label) = label {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
                 self.cbox(0);
                 self.ibox(0);
                 self.word_nbsp("for");
+                if kind == &ForLoopKind::ForAwait {
+                    self.word_nbsp("await");
+                }
                 self.print_pat(pat);
                 self.space();
                 self.word_space("in");
                 self.print_expr_as_cond(iter);
                 self.space();
-                self.print_block_with_attrs(blk, attrs);
+                self.print_block_with_attrs(body, attrs);
             }
             ast::ExprKind::Loop(blk, opt_label, _) => {
                 if let Some(label) = opt_label {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 247061c5ca7..43561a1c020 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -5,7 +5,6 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 use ast::StaticItem;
 use itertools::{Itertools, Position};
 use rustc_ast as ast;
-use rustc_ast::GenericBound;
 use rustc_ast::ModKind;
 use rustc_span::symbol::Ident;
 
@@ -338,21 +337,9 @@ impl<'a> State<'a> {
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                for bound in bounds.iter() {
-                    if let GenericBound::Trait(ptr, modifiers) = bound
-                        && let ast::BoundPolarity::Maybe(_) = modifiers.polarity
-                    {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(bound.clone());
-                    }
-                }
-                if !real_bounds.is_empty() {
+                if !bounds.is_empty() {
                     self.word_nbsp(":");
-                    self.print_type_bounds(&real_bounds);
+                    self.print_type_bounds(bounds);
                 }
                 self.print_where_clause(&generics.where_clause);
                 self.word(" ");
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 924e68fa91d..60dbf7dc055 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -408,13 +408,18 @@ fn try_extract_error_from_region_constraints<'tcx>(
     mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
     mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+    let placeholder_universe = match placeholder_region.kind() {
+        ty::RePlaceholder(p) => p.universe,
+        ty::ReVar(vid) => universe_of_region(vid),
+        _ => ty::UniverseIndex::ROOT,
+    };
     let matches =
         |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
             (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
             _ => a_region == b_region,
         };
-    let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
-        match *constraint {
+    let mut check =
+        |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
             Constraint::RegSubReg(sub, sup)
                 if ((exact && sup == placeholder_region)
                     || (!exact && matches(sup, placeholder_region)))
@@ -422,16 +427,16 @@ fn try_extract_error_from_region_constraints<'tcx>(
             {
                 Some((sub, cause.clone()))
             }
-            // FIXME: Should this check the universe of the var?
             Constraint::VarSubReg(vid, sup)
-                if ((exact && sup == placeholder_region)
-                    || (!exact && matches(sup, placeholder_region))) =>
+                if (exact
+                    && sup == placeholder_region
+                    && !universe_of_region(vid).can_name(placeholder_universe))
+                    || (!exact && matches(sup, placeholder_region)) =>
             {
                 Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
             }
             _ => None,
-        }
-    };
+        };
     let mut info = region_constraints
         .constraints
         .iter()
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index b54e119189a..d244897f8a5 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::Continue(_)
             | ExprKind::Err
             | ExprKind::Field(_, _)
-            | ExprKind::ForLoop(_, _, _, _)
+            | ExprKind::ForLoop { .. }
             | ExprKind::FormatArgs(_)
             | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 38c40471e29..60586f54fd5 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -357,6 +357,8 @@ declare_features! (
     (unstable, async_closure, "1.37.0", Some(62290)),
     /// Allows `#[track_caller]` on async functions.
     (unstable, async_fn_track_caller, "1.73.0", Some(110011)),
+    /// Allows `for await` loops.
+    (unstable, async_for_loop, "CURRENT_RUSTC_VERSION", Some(118898)),
     /// Allows builtin # foo() syntax
     (unstable, builtin_syntax, "1.71.0", Some(110680)),
     /// Treat `extern "C"` function as nounwind.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b0b53bb7478..7691cd11c4f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -307,6 +307,8 @@ language_item_table! {
     Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
+    AsyncIteratorPollNext,   sym::async_iterator_poll_next, async_iterator_poll_next, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0);
+
     Option,                  sym::Option,              option_type,                Target::Enum,           GenericRequirement::None;
     OptionSome,              sym::Some,                option_some_variant,        Target::Variant,        GenericRequirement::None;
     OptionNone,              sym::None,                option_none_variant,        Target::Variant,        GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 1d737e17e82..a82853a1303 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -124,7 +124,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     if let Some(term_did) = tcx.lang_items().termination() {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
-        let return_ty = return_ty.skip_binder();
+        let Some(return_ty) = return_ty.no_bound_vars() else {
+            tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
+            return;
+        };
         let infcx = tcx.infer_ctxt().build();
         let cause = traits::ObligationCause::new(
             return_ty_span,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 6715d01c9e0..feaec5ac620 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -553,17 +553,7 @@ impl<'a> State<'a> {
             }
             hir::ItemKind::OpaqueTy(opaque_ty) => {
                 self.print_item_type(item, opaque_ty.generics, |state| {
-                    let mut real_bounds = Vec::with_capacity(opaque_ty.bounds.len());
-                    for b in opaque_ty.bounds {
-                        if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
-                            state.space();
-                            state.word_space("for ?");
-                            state.print_trait_ref(&ptr.trait_ref);
-                        } else {
-                            real_bounds.push(b);
-                        }
-                    }
-                    state.print_bounds("= impl", real_bounds);
+                    state.print_bounds("= impl", opaque_ty.bounds)
                 });
             }
             hir::ItemKind::Enum(ref enum_definition, params) => {
@@ -625,17 +615,7 @@ impl<'a> State<'a> {
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                for b in bounds {
-                    if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b);
-                    }
-                }
-                self.print_bounds(":", real_bounds);
+                self.print_bounds(":", bounds);
                 self.print_where_clause(generics);
                 self.word(" ");
                 self.bopen();
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 0fbc4a0ce50..76d4dc24dce 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -135,6 +135,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     ) -> LexicalRegionResolutions<'tcx> {
         let mut var_data = self.construct_var_data();
 
+        // Deduplicating constraints is shown to have a positive perf impact.
+        self.data.constraints.sort_by_key(|(constraint, _)| *constraint);
+        self.data.constraints.dedup_by_key(|(constraint, _)| *constraint);
+
         if cfg!(debug_assertions) {
             self.dump_constraints();
         }
@@ -181,7 +185,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values);
         // Tracks the changed region vids.
         let mut changes = Vec::new();
-        for constraint in self.data.constraints.keys() {
+        for (constraint, _) in &self.data.constraints {
             match *constraint {
                 Constraint::RegSubVar(a_region, b_vid) => {
                     let b_data = var_values.value_mut(b_vid);
@@ -676,7 +680,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         let dummy_source = graph.add_node(());
         let dummy_sink = graph.add_node(());
 
-        for constraint in self.data.constraints.keys() {
+        for (constraint, _) in &self.data.constraints {
             match *constraint {
                 Constraint::VarSubVar(a_id, b_id) => {
                     graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint);
@@ -883,9 +887,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                     }
 
                     Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
+                        let constraint_idx =
+                            this.constraints.binary_search_by(|(c, _)| c.cmp(&edge.data)).unwrap();
                         state.result.push(RegionAndOrigin {
                             region,
-                            origin: this.constraints.get(&edge.data).unwrap().clone(),
+                            origin: this.constraints[constraint_idx].1.clone(),
                         });
                     }
 
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index e06596df7b9..b2bcbbf2e53 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -416,8 +416,8 @@ impl<'tcx> MiniGraph<'tcx> {
                 region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot)
             {
                 match undo_entry {
-                    AddConstraint(constraint) => {
-                        each_constraint(constraint);
+                    &AddConstraint(i) => {
+                        each_constraint(&region_constraints.data().constraints[i].0);
                     }
                     &AddVerify(i) => span_bug!(
                         region_constraints.data().verifys[i].origin.span(),
@@ -430,8 +430,8 @@ impl<'tcx> MiniGraph<'tcx> {
             region_constraints
                 .data()
                 .constraints
-                .keys()
-                .for_each(|constraint| each_constraint(constraint));
+                .iter()
+                .for_each(|(constraint, _)| each_constraint(constraint));
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index cbd8040c9f1..71adf526097 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -20,7 +20,6 @@ use rustc_middle::ty::{ReBound, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
 use rustc_span::Span;
 
-use std::collections::BTreeMap;
 use std::ops::Range;
 use std::{cmp, fmt, mem};
 
@@ -90,7 +89,7 @@ pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
 pub struct RegionConstraintData<'tcx> {
     /// Constraints of the form `A <= B`, where either `A` or `B` can
     /// be a region variable (or neither, as it happens).
-    pub constraints: BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
+    pub constraints: Vec<(Constraint<'tcx>, SubregionOrigin<'tcx>)>,
 
     /// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that
     /// `R0` must be equal to one of the regions `R1..Rn`. These occur
@@ -273,7 +272,7 @@ pub(crate) enum UndoLog<'tcx> {
     AddVar(RegionVid),
 
     /// We added the given `constraint`.
-    AddConstraint(Constraint<'tcx>),
+    AddConstraint(usize),
 
     /// We added the given `verify`.
     AddVerify(usize),
@@ -319,8 +318,9 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
                 self.var_infos.pop().unwrap();
                 assert_eq!(self.var_infos.len(), vid.index());
             }
-            AddConstraint(ref constraint) => {
-                self.data.constraints.remove(constraint);
+            AddConstraint(index) => {
+                self.data.constraints.pop().unwrap();
+                assert_eq!(self.data.constraints.len(), index);
             }
             AddVerify(index) => {
                 self.data.verifys.pop();
@@ -443,14 +443,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         // cannot add constraints once regions are resolved
         debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
 
-        // never overwrite an existing (constraint, origin) - only insert one if it isn't
-        // present in the map yet. This prevents origins from outside the snapshot being
-        // replaced with "less informative" origins e.g., during calls to `can_eq`
-        let undo_log = &mut self.undo_log;
-        self.storage.data.constraints.entry(constraint).or_insert_with(|| {
-            undo_log.push(AddConstraint(constraint));
-            origin
-        });
+        let index = self.storage.data.constraints.len();
+        self.storage.data.constraints.push((constraint, origin));
+        self.undo_log.push(AddConstraint(index));
     }
 
     fn add_verify(&mut self, verify: Verify<'tcx>) {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 34cdee4ec5c..0386f2ec56c 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -852,8 +852,8 @@ trait UnusedDelimLint {
                 (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
             }
 
-            ForLoop(_, ref cond, ref block, ..) => {
-                (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true)
+            ForLoop { ref iter, ref body, .. } => {
+                (iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
             }
 
             Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
@@ -1085,7 +1085,7 @@ impl EarlyLintPass for UnusedParens {
         }
 
         match e.kind {
-            ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop(ref pat, ..) => {
+            ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => {
                 self.check_unused_parens_pat(cx, pat, false, false, (true, true));
             }
             // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index c435f4023af..d67dc59c618 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -28,6 +28,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::Span;
 
 pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+    let typeck_results = tcx.typeck(def_id);
     let (thir, expr) = tcx.thir_body(def_id)?;
     let thir = thir.borrow();
     let pattern_arena = TypedArena::default();
@@ -35,6 +36,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
     let mut visitor = MatchVisitor {
         tcx,
         thir: &*thir,
+        typeck_results,
         param_env: tcx.param_env(def_id),
         lint_level: tcx.local_def_id_to_hir_id(def_id),
         let_source: LetSource::None,
@@ -80,6 +82,7 @@ enum LetSource {
 struct MatchVisitor<'thir, 'p, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
+    typeck_results: &'tcx ty::TypeckResults<'tcx>,
     thir: &'thir Thir<'tcx>,
     lint_level: HirId,
     let_source: LetSource,
@@ -382,6 +385,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
             scrutinee.map(|scrut| self.is_known_valid_scrutinee(scrut)).unwrap_or(true);
         MatchCheckCtxt {
             tcx: self.tcx,
+            typeck_results: self.typeck_results,
             param_env: self.param_env,
             module: self.tcx.parent_module(self.lint_level).to_def_id(),
             pattern_arena: self.pattern_arena,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a21a1533848..e653d4064c8 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -10,7 +10,7 @@ use super::{
 use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{noop_visit_expr, MutVisitor};
-use ast::{CoroutineKind, GenBlockKind, Pat, Path, PathSegment};
+use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
 use core::mem;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -1801,7 +1801,7 @@ impl<'a> Parser<'a> {
                     && matches!(
                         expr.kind,
                         ExprKind::While(_, _, None)
-                            | ExprKind::ForLoop(_, _, _, None)
+                            | ExprKind::ForLoop { label: None, .. }
                             | ExprKind::Loop(_, None, _)
                             | ExprKind::Block(_, None)
                     )
@@ -2685,8 +2685,17 @@ impl<'a> Parser<'a> {
         Ok((pat, expr))
     }
 
-    /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
+    /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
     fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+        let is_await =
+            self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await);
+
+        if is_await {
+            self.sess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
+        }
+
+        let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
+
         let (pat, expr) = self.parse_for_head()?;
         // Recover from missing expression in `for` loop
         if matches!(expr.kind, ExprKind::Block(..))
@@ -2699,13 +2708,13 @@ impl<'a> Parser<'a> {
             let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
             return Ok(self.mk_expr(
                 lo.to(self.prev_token.span),
-                ExprKind::ForLoop(pat, err_expr, block, opt_label),
+                ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind },
             ));
         }
 
         let (attrs, loop_block) = self.parse_inner_attrs_and_block()?;
 
-        let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label);
+        let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind };
 
         self.recover_loop_else("for", lo)?;
 
@@ -3800,7 +3809,7 @@ impl MutVisitor for CondChecker<'_> {
             | ExprKind::Lit(_)
             | ExprKind::If(_, _, _)
             | ExprKind::While(_, _, _)
-            | ExprKind::ForLoop(_, _, _, _)
+            | ExprKind::ForLoop { .. }
             | ExprKind::Loop(_, _, _)
             | ExprKind::Match(_, _)
             | ExprKind::Closure(_)
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 785a60e9978..f00e6f18617 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -62,7 +62,8 @@ pub trait TypeCx: Sized + Clone + fmt::Debug {
     /// patterns during analysis.
     type PatData: Clone + Default;
 
-    fn is_opaque_ty(ty: Self::Ty) -> bool;
+    /// FIXME(Nadrieril): `Cx` should only give us revealed types.
+    fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty;
     fn is_exhaustive_patterns_feature_on(&self) -> bool;
 
     /// The number of fields for this constructor.
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 072ef4836a8..450a5cb0a10 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -48,22 +48,14 @@ impl<'a, 'p, 'tcx> PatternColumn<'a, 'p, 'tcx> {
     fn is_empty(&self) -> bool {
         self.patterns.is_empty()
     }
-    fn head_ty(&self) -> Option<Ty<'tcx>> {
+    fn head_ty(&self, cx: MatchCtxt<'a, 'p, 'tcx>) -> Option<Ty<'tcx>> {
         if self.patterns.len() == 0 {
             return None;
         }
-        // If the type is opaque and it is revealed anywhere in the column, we take the revealed
-        // version. Otherwise we could encounter constructors for the revealed type and crash.
-        let first_ty = self.patterns[0].ty();
-        if RustcMatchCheckCtxt::is_opaque_ty(first_ty) {
-            for pat in &self.patterns {
-                let ty = pat.ty();
-                if !RustcMatchCheckCtxt::is_opaque_ty(ty) {
-                    return Some(ty);
-                }
-            }
-        }
-        Some(first_ty)
+
+        let ty = self.patterns[0].ty();
+        // FIXME(Nadrieril): `Cx` should only give us revealed types.
+        Some(cx.tycx.reveal_opaque_ty(ty))
     }
 
     /// Do constructor splitting on the constructors of the column.
@@ -125,7 +117,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
     cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'a, 'p, 'tcx>,
 ) -> Vec<WitnessPat<'p, 'tcx>> {
-    let Some(ty) = column.head_ty() else {
+    let Some(ty) = column.head_ty(cx) else {
         return Vec::new();
     };
     let pcx = &PlaceCtxt::new_dummy(cx, ty);
@@ -226,7 +218,7 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
     cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'a, 'p, 'tcx>,
 ) {
-    let Some(ty) = column.head_ty() else {
+    let Some(ty) = column.head_ty(cx) else {
         return;
     };
     let pcx = &PlaceCtxt::new_dummy(cx, ty);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 65c90aa9f1d..d2cfb9a8b06 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -44,6 +44,7 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, '
 #[derive(Clone)]
 pub struct RustcMatchCheckCtxt<'p, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
+    pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
     /// The module in which the match occurs. This is necessary for
     /// checking inhabited-ness of types because whether a type is (visibly)
     /// inhabited can depend on whether it was defined in the current module or
@@ -101,6 +102,21 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
         }
     }
 
+    /// Type inference occasionally gives us opaque types in places where corresponding patterns
+    /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
+    /// types, we use the corresponding concrete type if possible.
+    fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
+            if let Some(local_def_id) = alias_ty.def_id.as_local() {
+                let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
+                if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
+                    return real_ty.ty;
+                }
+            }
+        }
+        ty
+    }
+
     // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
     // uninhabited fields in order not to reveal the uninhabitedness of the whole variant.
     // This lists the fields we keep along with their types.
@@ -873,8 +889,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
         self.tcx.features().exhaustive_patterns
     }
-    fn is_opaque_ty(ty: Self::Ty) -> bool {
-        matches!(ty.kind(), ty::Alias(ty::Opaque, ..))
+
+    fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.reveal_opaque_ty(ty)
     }
 
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: Self::Ty) -> usize {
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 6b1de807797..6b9fbd73003 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -865,24 +865,14 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
         matrix
     }
 
-    fn head_ty(&self) -> Option<Cx::Ty> {
+    fn head_ty(&self, mcx: MatchCtxt<'a, 'p, Cx>) -> Option<Cx::Ty> {
         if self.column_count() == 0 {
             return None;
         }
 
-        let mut ty = self.wildcard_row.head().ty();
-        // If the type is opaque and it is revealed anywhere in the column, we take the revealed
-        // version. Otherwise we could encounter constructors for the revealed type and crash.
-        if Cx::is_opaque_ty(ty) {
-            for pat in self.heads() {
-                let pat_ty = pat.ty();
-                if !Cx::is_opaque_ty(pat_ty) {
-                    ty = pat_ty;
-                    break;
-                }
-            }
-        }
-        Some(ty)
+        let ty = self.wildcard_row.head().ty();
+        // FIXME(Nadrieril): `Cx` should only give us revealed types.
+        Some(mcx.tycx.reveal_opaque_ty(ty))
     }
     fn column_count(&self) -> usize {
         self.wildcard_row.len()
@@ -1181,7 +1171,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
 ) -> WitnessMatrix<Cx> {
     debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
 
-    let Some(ty) = matrix.head_ty() else {
+    let Some(ty) = matrix.head_ty(mcx) else {
         // The base case: there are no columns in the matrix. We are morally pattern-matching on ().
         // A row is useful iff it has no (unguarded) rows above it.
         for row in matrix.rows_mut() {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index cf50f630bf2..bd4a2998e2d 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4258,11 +4258,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 });
             }
 
-            ExprKind::ForLoop(ref pat, ref iter_expr, ref block, label) => {
-                self.visit_expr(iter_expr);
+            ExprKind::ForLoop { ref pat, ref iter, ref body, label, kind: _ } => {
+                self.visit_expr(iter);
                 self.with_rib(ValueNS, RibKind::Normal, |this| {
                     this.resolve_pattern_top(pat, PatternSource::For);
-                    this.resolve_labeled_block(label, expr.id, block);
+                    this.resolve_labeled_block(label, expr.id, body);
                 });
             }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 376ccfba9d8..5a02e7f3269 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1409,7 +1409,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             | ExprKind::Unary(..)
                             | ExprKind::If(..)
                             | ExprKind::While(..)
-                            | ExprKind::ForLoop(..)
+                            | ExprKind::ForLoop { .. }
                             | ExprKind::Match(..),
                         ..
                     }),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0333b5f04c3..95106cc64c1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -426,7 +426,9 @@ symbols! {
         async_closure,
         async_fn_in_trait,
         async_fn_track_caller,
+        async_for_loop,
         async_iterator,
+        async_iterator_poll_next,
         atomic,
         atomic_mod,
         atomics,
@@ -893,6 +895,7 @@ symbols! {
         instruction_set,
         integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below
         integral,
+        into_async_iter_into_iter,
         into_future,
         into_iter,
         intra_doc_pointers,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index b688c97311a..f3866f4904b 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1493,6 +1493,7 @@ supported_targets! {
     ("mips64-unknown-linux-muslabi64", mips64_unknown_linux_muslabi64),
     ("mips64el-unknown-linux-muslabi64", mips64el_unknown_linux_muslabi64),
     ("hexagon-unknown-linux-musl", hexagon_unknown_linux_musl),
+    ("hexagon-unknown-none-elf", hexagon_unknown_none_elf),
 
     ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc),
     ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc),
diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
new file mode 100644
index 00000000000..205f195a701
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
@@ -0,0 +1,27 @@
+use crate::spec::{PanicStrategy, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "hexagon-unknown-none-elf".into(),
+        pointer_width: 32,
+        data_layout: concat!(
+            "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32",
+            ":32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32",
+            ":32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048",
+            ":2048:2048"
+        )
+        .into(),
+        arch: "hexagon".into(),
+
+        options: TargetOptions {
+            cpu: "hexagonv60".into(),
+            panic_strategy: PanicStrategy::Abort,
+            dynamic_linking: true,
+            features: "-small-data,+hvx-length128b".into(),
+            max_atomic_width: Some(32),
+            emit_debug_gdb_scripts: false,
+            c_enum_min_bits: Some(8),
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 257867b1b80..3fefd60f7cd 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -116,7 +116,8 @@ impl Target {
 
         // Check dynamic linking stuff
         // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries.
-        if self.os == "none" && self.arch != "bpf" {
+        // hexagon: when targeting QuRT, that OS can load dynamic libraries.
+        if self.os == "none" && (self.arch != "bpf" && self.arch != "hexagon") {
             assert!(!self.dynamic_linking);
         }
         if self.only_cdylib
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 13a09917c03..c6d029ddb65 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -477,7 +477,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default();
         let mut finished_map = FxHashMap::default();
 
-        for constraint in regions.constraints.keys() {
+        for (constraint, _) in &regions.constraints {
             match constraint {
                 &Constraint::VarSubVar(r1, r2) => {
                     {
diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs
index a8197332fd0..a7512ef6a24 100644
--- a/library/core/src/async_iter/async_iter.rs
+++ b/library/core/src/async_iter/async_iter.rs
@@ -47,6 +47,7 @@ pub trait AsyncIterator {
     /// Rust's usual rules apply: calls must never cause undefined behavior
     /// (memory corruption, incorrect use of `unsafe` functions, or the like),
     /// regardless of the async iterator's state.
+    #[cfg_attr(not(bootstrap), lang = "async_iterator_poll_next")]
     fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
 
     /// Returns the bounds on the remaining length of the async iterator.
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index cf3f5bc983e..57e63927c95 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1001,6 +1001,7 @@ tool_doc!(
         "cargo-test-macro",
         "cargo-test-support",
         "cargo-util",
+        "cargo-util-schemas",
         "crates-io",
         "mdman",
         "rustfix",
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 800d8920951..3af370bf006 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -471,6 +471,11 @@ jobs:
             <<: *job-linux-4c
 
           - name: x86_64-gnu-integration
+            env:
+              # Only run this job on the nightly channel. Fuchsia requires
+              # nightly features to compile, and this job would fail if
+              # executed on beta and stable.
+              CI_ONLY_WHEN_CHANNEL: nightly
             <<: *job-linux-16c
 
           - name: x86_64-gnu-debug
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index fadd64a0353..1c8e1d1e316 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -38,6 +38,7 @@
     - [\*-unknown-fuchsia](platform-support/fuchsia.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [csky-unknown-linux-gnuabiv2\*](platform-support/csky-unknown-linux-gnuabiv2.md)
+    - [hexagon-unknown-none-elf](platform-support/hexagon-unknown-none-elf.md)
     - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md)
     - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 59ef7441024..78c041ee511 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -265,6 +265,7 @@ target | std | host | notes
 `bpfel-unknown-none` | * |  | BPF (little endian)
 `csky-unknown-linux-gnuabiv2` | ✓ |  | C-SKY abiv2 Linux (little endian)
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
+[`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | Bare Hexagon (v60+, HVX)
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
 [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS  [^x86_32-floats-return-ABI]
diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md
new file mode 100644
index 00000000000..06423f0f8fa
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md
@@ -0,0 +1,266 @@
+# `hexagon-unknown-none-elf`
+
+**Tier: 3**
+
+Rust for baremetal Hexagon DSPs.
+
+| Target                   | Descriptions                              |
+| ------------------------ | ----------------------------------------- |
+| hexagon-unknown-none-elf | Hexagon 32-bit (freestanding, hardfloat)  |
+
+## Target maintainers
+
+- [Brian Cain](https://github.com/androm3da), `bcain@quicinc.com`
+
+## Requirements
+
+This target is cross-compiled.  There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+By default, code generated with this target should run on Hexagon DSP hardware.
+
+- `-Ctarget-cpu=hexagonv73` adds support for instructions defined up to Hexagon V73.
+
+Functions marked `extern "C"` use the [Hexagon architecture calling convention](https://lists.llvm.org/pipermail/llvm-dev/attachments/20190916/21516a52/attachment-0001.pdf).
+
+This target generates PIC ELF binaries.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+host = ["<target for your host>"]
+target = ["<target for your host>", "hexagon-unknown-none-elf"]
+
+[target.hexagon-unknown-none-elf]
+
+cc = "hexagon-unknown-none-elf-clang"
+cxx = "hexagon-unknown-none-elf-clang++"
+linker = "hexagon-unknown-none-elf-clang"
+llvm-libunwind = 'in-tree'
+```
+
+Replace `<target for your host>` with `x86_64-unknown-linux-gnu` or whatever
+else is appropriate for your host machine.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Since `hexagon-unknown-none-elf` supports a variety of different environments and
+does not support `std`, this target does not support running the Rust test suite.
+
+## Cross-compilation toolchains and C code
+
+This target has been tested using `qemu-system-hexagon`.
+
+A common use case for `hexagon-unknown-none-elf` is building libraries that
+link against C code and can be used in emulation or on a device with a
+Hexagon DSP.
+
+The Hexagon SDK has libraries which are useful to link against when running
+on a device.
+
+
+# Standalone OS
+
+The script below will build an executable against "hexagon standalone OS"
+which is suitable for emulation or bare-metal on-device testing.
+
+First, run `cargo new --bin demo1_hexagon` then add the source below as
+`src/main.rs`.  This program demonstrates the console output via semihosting.
+
+```rust,ignore (platform-specific,eh-personality-is-unstable)
+#![no_std]
+#![no_main]
+
+extern "C" {
+    fn putchar(ch: i32);
+    fn _exit(code: i32) -> !;
+}
+
+#[no_mangle]
+extern "C" fn main() -> i32 {
+    let message = "Hello, this is Rust!";
+    for b in message.bytes() {
+        unsafe {
+            putchar(b as i32);
+        }
+    }
+    0
+}
+
+#[panic_handler]
+fn panic(_panic: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        _exit(1);
+    }
+}
+
+```
+
+Next, save the script below as `build.sh` and edit it to suit your
+environment.
+
+* `hex_toolchain` below refers to the [hexagon toolchain using exclusively
+public open source repos](https://github.com/quic/toolchain_for_hexagon/releases).
+* `cc` below refers to clang.  You can use `clang` from your distribution, as
+long as it's at least `clang-17`.  Or you can use
+`hexagon-unknown-none-elf-clang` from one of the [hexagon open source toolchain
+releases](https://github.com/quic/toolchain_for_hexagon/releases).
+
+```sh
+# Hexagon SDK, required for target libraries:
+hex_sdk_root=/local/mnt/workspace/Qualcomm/Hexagon_SDK/5.3.0.0
+hex_sdk_toolchain=${hex_sdk_root}/tools/HEXAGON_Tools/8.6.06
+
+sdk_libs=${hex_sdk_toolchain}/Tools/target/hexagon/lib
+q6_arch=v65
+g0_lib_path=${sdk_libs}/${q6_arch}/G0
+pic_lib_path=${sdk_libs}/${q6_arch}/G0/pic
+
+cargo build --target=hexagon-unknown-none-elf -Zbuild-std
+
+# Builds an executable against "hexagon standalone OS" suitable for emulation:
+${cc} --target=hexagon-unknown-none-elf -o testit \
+    -fuse-ld=lld \
+    -m${q6_arch} \
+    -nodefaultlibs \
+    -nostartfiles \
+    ${g0_lib_path}/crt0_standalone.o \
+    ${g0_lib_path}/crt0.o \
+    ${g0_lib_path}/init.o \
+    -L${sdk_libs}/${q6_arch}/ \
+    -L${sdk_libs}/ \
+    testit.c \
+    target/hexagon-unknown-none-elf/debug/libmin_ex_lib_lin.rlib \
+    target/hexagon-unknown-none-elf/debug/deps/libcore-*.rlib \
+    target/hexagon-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib \
+    -Wl,--start-group \
+    -Wl,--defsym,_SDA_BASE_=0,--defsym,__sbss_start=0,--defsym,__sbss_end=0 \
+    -lstandalone \
+    ${g0_lib_path}/libc.a \
+    -lgcc \
+    -lc_eh \
+    -Wl,--end-group \
+    ${g0_lib_path}/fini.o \
+
+${hex_toolchain}/x86_64-linux-gnu/bin/qemu-system-hexagon -monitor none -display none -kernel ./testit
+```
+
+# QuRT OS
+
+First, run `cargo new --lib demo2_hexagon` then add the source below as
+`src/lib.rs`.  This program demonstrates inline assembly and console output
+via semihosting.
+
+```rust,ignore (platform-specific,eh-personality-is-unstable)
+#![no_std]
+#![no_main]
+#![feature(lang_items)]
+#![feature(asm_experimental_arch)]
+
+use core::arch::asm;
+
+extern "C" {
+    fn putchar(ch: i32);
+    fn _exit(code: i32) -> !;
+}
+
+fn hexagon_specific() {
+    let mut buffer = [0_u8; 128];
+
+    unsafe {
+        let mut x = &buffer;
+        asm!(
+                "{{\n\t",
+                "  v0=vmem({addr}+#0)\n\t",
+                "  {tmp} = and({tmp}, #1)\n\t",
+                "}}\n\t",
+                addr = in(reg) x,
+                tmp = out(reg) _,
+            );
+    }
+}
+
+#[no_mangle]
+extern "C" fn hello() -> i32 {
+    let message = "Hello, this is Rust!\n";
+    for b in message.bytes() {
+        unsafe {
+            putchar(b as i32);
+        }
+    }
+    hexagon_specific();
+    0
+}
+
+#[panic_handler]
+fn panic(_panic: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        _exit(1);
+    }
+}
+
+#[lang = "eh_personality"]
+fn rust_eh_personality() {}
+
+```
+
+Next, save the script below as `build.sh` and edit it to suit your
+environment.  The script below will build a shared object against the QuRT
+RTOS which is suitable for emulation or on-device testing when loaded via
+the fastrpc-shell.
+
+
+```sh
+# Hexagon SDK, required for target libraries:
+hex_sdk_root=/local/mnt/workspace/Qualcomm/Hexagon_SDK/5.3.0.0
+hex_sdk_toolchain=${hex_sdk_root}/tools/HEXAGON_Tools/8.6.06
+
+sdk_libs=${hex_sdk_toolchain}/Tools/target/hexagon/lib
+q6_arch=v65
+g0_lib_path=${sdk_libs}/${q6_arch}/G0
+pic_lib_path=${sdk_libs}/${q6_arch}/G0/pic
+runelf=${hex_sdk_root}/rtos/qurt/computev65/sdksim_bin/runelf.pbn
+rmohs=${hex_sdk_root}/libs/run_main_on_hexagon/ship/hexagon_toolv86_${q6_arch}/run_main_on_hexagon_sim
+
+# Builds a library suitable for loading into "run_main_on_hexagon_sim" for
+# emulation or frpc shell on real target:
+${cc} --target=hexagon-unknown-none-elf -o testit.so \
+    -fuse-ld=lld \
+    -fPIC -shared \
+    -nostdlib \
+    -Wl,-Bsymbolic \
+      -Wl,--wrap=malloc \
+      -Wl,--wrap=calloc \
+      -Wl,--wrap=free \
+      -Wl,--wrap=realloc \
+      -Wl,--wrap=memalign \
+    -m${q6_arch} \
+    testit.c \
+    target/hexagon-unknown-none-elf/debug/libmin_ex_lib_lin.rlib \
+    target/hexagon-unknown-none-elf/debug/deps/libcore-*.rlib \
+    target/hexagon-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib \
+    -Wl,-soname=testit \
+    ${pic_lib_path}/libc.so
+
+# -Bsymbolic above for memory alloc funcs is necessary to access the heap on
+# target, but otherwise not required.
+
+# multi-stage loader: runelf => run_main_on_hexagon_sim => testit.so{`main`}
+${hex_toolchain}/x86_64-linux-gnu/bin/qemu-system-hexagon \
+    -monitor none \
+    -display none \
+    -kernel ${runelf} \
+    -append "${rmohs} -- ./testit.so"
+```
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index e692f4ef72e..9de547ba6dc 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -195,7 +195,7 @@ where
         // into a map. Each RegionTarget (either a RegionVid or a Region) maps
         // to its smaller and larger regions. Note that 'larger' regions correspond
         // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
-        for constraint in regions.constraints.keys() {
+        for (constraint, _) in &regions.constraints {
             match *constraint {
                 Constraint::VarSubVar(r1, r2) => {
                     {
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 1a2666ddd14cf0a255d4ddb61c63531c259a7b3
+Subproject 363a2d11320faf531f6aacd1ea067c6bc08343b
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 4b9ab50e4fd..ff72b5e69ef 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -220,7 +220,11 @@ where
     F: FnMut(&ast::Block, Option<&ast::Label>),
 {
     if let ast::ExprKind::While(_, loop_block, label)
-    | ast::ExprKind::ForLoop(_, _, loop_block, label)
+    | ast::ExprKind::ForLoop {
+        body: loop_block,
+        label,
+        ..
+    }
     | ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
     {
         func(loop_block, label.as_ref());
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 001686c84f8..fb434fb7450 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -111,7 +111,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
             ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
             ExprKind::If(_, _, None)
             // ignore loops for simplicity
-            | ExprKind::While(..) | ExprKind::ForLoop(..) | ExprKind::Loop(..) => false,
+            | ExprKind::While(..) | ExprKind::ForLoop { .. } | ExprKind::Loop(..) => false,
             _ => {
                 walk_expr(self, expr);
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 8b9d9bade91..60e9d262e7e 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -554,7 +554,7 @@ fn ident_difference_expr_with_base_location(
         | (Closure(_), Closure(_))
         | (Match(_, _), Match(_, _))
         | (Loop(_, _, _), Loop(_, _, _))
-        | (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
+        | (ForLoop { .. }, ForLoop { .. })
         | (While(_, _, _), While(_, _, _))
         | (If(_, _, _), If(_, _, _))
         | (Let(_, _, _, _), Let(_, _, _, _))
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index c271e498665..7fe76b946a4 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -169,9 +169,22 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
         (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
         (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
-        (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
-            eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
-        },
+        (
+            ForLoop {
+                pat: lp,
+                iter: li,
+                body: lt,
+                label: ll,
+                kind: lk,
+            },
+            ForLoop {
+                pat: rp,
+                iter: ri,
+                body: rt,
+                label: rl,
+                kind: rk,
+            },
+        ) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
         (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
         (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
         (TryBlock(l), TryBlock(r)) => eq_block(l, r),
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 9b2bc8df1f3..c86362c427c 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -197,7 +197,7 @@ impl<'a> Sugg<'a> {
             | ast::ExprKind::Continue(..)
             | ast::ExprKind::Yield(..)
             | ast::ExprKind::Field(..)
-            | ast::ExprKind::ForLoop(..)
+            | ast::ExprKind::ForLoop { .. }
             | ast::ExprKind::Index(..)
             | ast::ExprKind::InlineAsm(..)
             | ast::ExprKind::OffsetOf(..)
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index f698f494ae5..5bf29441b54 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -448,7 +448,7 @@ fn is_block_closure_forced(context: &RewriteContext<'_>, expr: &ast::Expr) -> bo
 
 fn is_block_closure_forced_inner(expr: &ast::Expr, version: Version) -> bool {
     match expr.kind {
-        ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop(..) => true,
+        ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop { .. } => true,
         ast::ExprKind::Loop(..) if version == Version::Two => true,
         ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Try(ref expr)
@@ -473,7 +473,7 @@ fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
         | ast::ExprKind::Block(..)
         | ast::ExprKind::While(..)
         | ast::ExprKind::Loop(..)
-        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::ForLoop { .. }
         | ast::ExprKind::TryBlock(..) => false,
         _ => true,
     }
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index a68bd6694ba..7808f891336 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -3,7 +3,7 @@ use std::cmp::min;
 
 use itertools::Itertools;
 use rustc_ast::token::{Delimiter, Lit, LitKind};
-use rustc_ast::{ast, ptr, token};
+use rustc_ast::{ast, ptr, token, ForLoopKind};
 use rustc_span::{BytePos, Span};
 
 use crate::chains::rewrite_chain;
@@ -134,7 +134,7 @@ pub(crate) fn format_expr(
         }
         ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
         ast::ExprKind::If(..)
-        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::ForLoop { .. }
         | ast::ExprKind::Loop(..)
         | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
             .and_then(|control_flow| control_flow.rewrite(context, shape)),
@@ -682,9 +682,15 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<
                 expr.span,
             ))
         }
-        ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
-            Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
-        }
+        ast::ExprKind::ForLoop {
+            ref pat,
+            ref iter,
+            ref body,
+            label,
+            kind,
+        } => Some(ControlFlow::new_for(
+            pat, iter, body, label, expr.span, kind,
+        )),
         ast::ExprKind::Loop(ref block, label, _) => {
             Some(ControlFlow::new_loop(block, label, expr.span))
         }
@@ -771,6 +777,7 @@ impl<'a> ControlFlow<'a> {
         block: &'a ast::Block,
         label: Option<ast::Label>,
         span: Span,
+        kind: ForLoopKind,
     ) -> ControlFlow<'a> {
         ControlFlow {
             cond: Some(cond),
@@ -778,7 +785,10 @@ impl<'a> ControlFlow<'a> {
             else_block: None,
             label,
             pat: Some(pat),
-            keyword: "for",
+            keyword: match kind {
+                ForLoopKind::For => "for",
+                ForLoopKind::ForAwait => "for await",
+            },
             matcher: "",
             connector: " in",
             allow_single_line: false,
@@ -1364,7 +1374,7 @@ pub(crate) fn can_be_overflowed_expr(
                 || context.config.overflow_delimited_expr()
         }
         ast::ExprKind::If(..)
-        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::ForLoop { .. }
         | ast::ExprKind::Loop(..)
         | ast::ExprKind::While(..) => {
             context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs
index ef509b56837..5a00984d4c0 100644
--- a/src/tools/rustfmt/src/matches.rs
+++ b/src/tools/rustfmt/src/matches.rs
@@ -591,7 +591,7 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool {
         ast::ExprKind::If(..) => false,
         // We do not allow collapsing a block around expression with condition
         // to avoid it being cluttered with match arm.
-        ast::ExprKind::ForLoop(..) | ast::ExprKind::While(..) => false,
+        ast::ExprKind::ForLoop { .. } | ast::ExprKind::While(..) => false,
         ast::ExprKind::Loop(..)
         | ast::ExprKind::Match(..)
         | ast::ExprKind::Block(..)
diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs
index d81bf24dbd1..f46583b1c89 100644
--- a/src/tools/rustfmt/src/overflow.rs
+++ b/src/tools/rustfmt/src/overflow.rs
@@ -409,7 +409,7 @@ impl<'a> Context<'a> {
                     // When overflowing the expressions which consists of a control flow
                     // expression, avoid condition to use multi line.
                     ast::ExprKind::If(..)
-                    | ast::ExprKind::ForLoop(..)
+                    | ast::ExprKind::ForLoop { .. }
                     | ast::ExprKind::Loop(..)
                     | ast::ExprKind::While(..)
                     | ast::ExprKind::Match(..) => {
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 7d7bbf11529..642b6603b1e 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -295,7 +295,7 @@ pub(crate) fn semicolon_for_stmt(
 ) -> bool {
     match stmt.kind {
         ast::StmtKind::Semi(ref expr) => match expr.kind {
-            ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) => {
+            ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop { .. } => {
                 false
             }
             ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
@@ -476,7 +476,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::ConstBlock(..)
         | ast::ExprKind::Gen(..)
         | ast::ExprKind::Loop(..)
-        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::ForLoop { .. }
         | ast::ExprKind::TryBlock(..)
         | ast::ExprKind::Match(..) => repr.contains('\n'),
         ast::ExprKind::Paren(ref expr)
diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs
index c94dfd85e7d..89e49738991 100644
--- a/tests/codegen/overaligned-constant.rs
+++ b/tests/codegen/overaligned-constant.rs
@@ -17,7 +17,7 @@ fn main() {
     // CHECK: [[full:%_.*]] = alloca %SmallStruct, align 8
     // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 @0, i64 32, i1 false)
     // CHECK: %b.0 = load i32, ptr @0, align 4,
-    // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({ i32, i32 }, ptr @0, i32 0, i32 1), align 4
+    // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({{.*}}), align 4
     let mut s = S(1);
 
     s.0 = 3;
diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs
new file mode 100644
index 00000000000..42247dd14b0
--- /dev/null
+++ b/tests/ui/async-await/feature-async-for-loop.rs
@@ -0,0 +1,23 @@
+// edition:2021
+// gate-test-async_for_loop
+
+#![feature(async_iter_from_iter, async_iterator)]
+
+fn f() {
+    let _ = async {
+        for await _i in core::async_iter::from_iter(0..3) {
+            //~^ ERROR `for await` loops are experimental
+        }
+    };
+}
+
+#[cfg(FALSE)]
+fn g() {
+    let _ = async {
+        for await _i in core::async_iter::from_iter(0..3) {
+            //~^ ERROR `for await` loops are experimental
+        }
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/feature-async-for-loop.stderr b/tests/ui/async-await/feature-async-for-loop.stderr
new file mode 100644
index 00000000000..38f75821772
--- /dev/null
+++ b/tests/ui/async-await/feature-async-for-loop.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `for await` loops are experimental
+  --> $DIR/feature-async-for-loop.rs:8:13
+   |
+LL |         for await _i in core::async_iter::from_iter(0..3) {
+   |             ^^^^^
+   |
+   = note: see issue #118898 <https://github.com/rust-lang/rust/issues/118898> for more information
+   = help: add `#![feature(async_for_loop)]` to the crate attributes to enable
+
+error[E0658]: `for await` loops are experimental
+  --> $DIR/feature-async-for-loop.rs:17:13
+   |
+LL |         for await _i in core::async_iter::from_iter(0..3) {
+   |             ^^^^^
+   |
+   = note: see issue #118898 <https://github.com/rust-lang/rust/issues/118898> for more information
+   = help: add `#![feature(async_for_loop)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/for-await-2015.rs b/tests/ui/async-await/for-await-2015.rs
new file mode 100644
index 00000000000..c1b7c016d1f
--- /dev/null
+++ b/tests/ui/async-await/for-await-2015.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(async_for_loop)]
+
+// Make sure we don't break `for await` loops in the 2015 edition, where `await` was allowed as an
+// identifier.
+
+fn main() {
+    for await in 0..3 {}
+}
diff --git a/tests/ui/async-await/for-await-consumes-iter.rs b/tests/ui/async-await/for-await-consumes-iter.rs
new file mode 100644
index 00000000000..65bb9e88448
--- /dev/null
+++ b/tests/ui/async-await/for-await-consumes-iter.rs
@@ -0,0 +1,20 @@
+// edition: 2021
+#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker)]
+
+use std::future::Future;
+
+// a test to make sure `for await` consumes the iterator
+
+async fn real_main() {
+    let iter = core::async_iter::from_iter(0..3);
+    let mut count = 0;
+    for await i in iter {
+    }
+    // make sure iter has been moved and we can't iterate over it again.
+    for await i in iter {
+        //~^ ERROR: use of moved value: `iter`
+    }
+}
+
+fn main() {
+}
diff --git a/tests/ui/async-await/for-await-consumes-iter.stderr b/tests/ui/async-await/for-await-consumes-iter.stderr
new file mode 100644
index 00000000000..48b2e8a51d8
--- /dev/null
+++ b/tests/ui/async-await/for-await-consumes-iter.stderr
@@ -0,0 +1,27 @@
+error[E0382]: use of moved value: `iter`
+  --> $DIR/for-await-consumes-iter.rs:14:20
+   |
+LL |     let iter = core::async_iter::from_iter(0..3);
+   |         ---- move occurs because `iter` has type `FromIter<std::ops::Range<i32>>`, which does not implement the `Copy` trait
+LL |     let mut count = 0;
+LL |     for await i in iter {
+   |     -------------------
+   |     |              |
+   |     |              value moved here
+   |     inside of this loop
+...
+LL |     for await i in iter {
+   |                    ^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     for await i in iter.clone() {
+   |                        ++++++++
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     for await i in ref iter {
+   |                    +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/async-await/for-await-passthrough.rs b/tests/ui/async-await/for-await-passthrough.rs
new file mode 100644
index 00000000000..7fa133aaedc
--- /dev/null
+++ b/tests/ui/async-await/for-await-passthrough.rs
@@ -0,0 +1,32 @@
+// run-pass
+// edition: 2024
+// compile-flags: -Zunstable-options
+#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker,
+           gen_blocks)]
+
+use std::future::Future;
+
+async gen fn async_iter() -> i32 {
+    let iter = core::async_iter::from_iter(0..3);
+    for await i in iter {
+        yield i + 1;
+    }
+}
+
+// make sure a simple for await loop works
+async fn real_main() {
+    let mut count = 1;
+    for await i in async_iter() {
+        assert_eq!(i, count);
+        count += 1;
+    }
+    assert_eq!(count, 4);
+}
+
+fn main() {
+    let future = real_main();
+    let waker = std::task::Waker::noop();
+    let mut cx = &mut core::task::Context::from_waker(&waker);
+    let mut future = core::pin::pin!(future);
+    while let core::task::Poll::Pending = future.as_mut().poll(&mut cx) {}
+}
diff --git a/tests/ui/async-await/for-await.rs b/tests/ui/async-await/for-await.rs
new file mode 100644
index 00000000000..6345ceb0c27
--- /dev/null
+++ b/tests/ui/async-await/for-await.rs
@@ -0,0 +1,24 @@
+// run-pass
+// edition: 2021
+#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker)]
+
+use std::future::Future;
+
+// make sure a simple for await loop works
+async fn real_main() {
+    let iter = core::async_iter::from_iter(0..3);
+    let mut count = 0;
+    for await i in iter {
+        assert_eq!(i, count);
+        count += 1;
+    }
+    assert_eq!(count, 3);
+}
+
+fn main() {
+    let future = real_main();
+    let waker = std::task::Waker::noop();
+    let mut cx = &mut core::task::Context::from_waker(&waker);
+    let mut future = core::pin::pin!(future);
+    while let core::task::Poll::Pending = future.as_mut().poll(&mut cx) {}
+}
diff --git a/tests/ui/entry-point/return-ty-has-bound-vars.rs b/tests/ui/entry-point/return-ty-has-bound-vars.rs
new file mode 100644
index 00000000000..0995ce06160
--- /dev/null
+++ b/tests/ui/entry-point/return-ty-has-bound-vars.rs
@@ -0,0 +1,3 @@
+// issue-119209
+
+fn main<'a>(_: &'a i32) -> &'a () { &() } //~ERROR `main` function return type is not allowed to have generic parameters
diff --git a/tests/ui/entry-point/return-ty-has-bound-vars.stderr b/tests/ui/entry-point/return-ty-has-bound-vars.stderr
new file mode 100644
index 00000000000..e7aab839f31
--- /dev/null
+++ b/tests/ui/entry-point/return-ty-has-bound-vars.stderr
@@ -0,0 +1,9 @@
+error[E0131]: `main` function return type is not allowed to have generic parameters
+  --> $DIR/return-ty-has-bound-vars.rs:3:28
+   |
+LL | fn main<'a>(_: &'a i32) -> &'a () { &() }
+   |                            ^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0131`.
diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
index d0892fd8b09..c25e731d962 100644
--- a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
+++ b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     assert_all::<_, &String>(id);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected reference `&String`
-              found reference `&String`
+   = note: expected trait `for<'a> <for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>`
+              found trait `for<'a> <for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs
new file mode 100644
index 00000000000..6e8c0feb710
--- /dev/null
+++ b/tests/ui/pattern/usefulness/impl-trait.rs
@@ -0,0 +1,146 @@
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+#![feature(type_alias_impl_trait)]
+#![feature(non_exhaustive_omitted_patterns_lint)]
+#![deny(unreachable_patterns)]
+// Test that the lint traversal handles opaques correctly
+#![deny(non_exhaustive_omitted_patterns)]
+
+fn main() {}
+
+#[derive(Copy, Clone)]
+enum Void {}
+
+fn return_never_rpit(x: Void) -> impl Copy {
+    if false {
+        match return_never_rpit(x) {
+            _ => {} //~ ERROR unreachable
+        }
+    }
+    x
+}
+fn friend_of_return_never_rpit(x: Void) {
+    match return_never_rpit(x) {}
+    //~^ ERROR non-empty
+}
+
+type T = impl Copy;
+fn return_never_tait(x: Void) -> T {
+    if false {
+        match return_never_tait(x) {
+            _ => {} //~ ERROR unreachable
+        }
+    }
+    x
+}
+fn friend_of_return_never_tait(x: Void) {
+    match return_never_tait(x) {}
+    //~^ ERROR non-empty
+}
+
+fn option_never(x: Void) -> Option<impl Copy> {
+    if false {
+        match option_never(x) {
+            None => {}
+            Some(_) => {} //~ ERROR unreachable
+        }
+        match option_never(x) {
+            None => {}
+            // FIXME: Unreachable not detected because `is_uninhabited` does not look into opaque
+            // types.
+            _ => {}
+        }
+    }
+    Some(x)
+}
+
+fn option_never2(x: Void) -> impl Copy {
+    if false {
+        match option_never2(x) {
+            None => {}
+            Some(_) => {} //~ ERROR unreachable
+        }
+        match option_never2(x) {
+            None => {}
+            _ => {} //~ ERROR unreachable
+        }
+        match option_never2(x) {
+            None => {}
+        }
+    }
+    Some(x)
+}
+
+fn inner_never(x: Void) {
+    type T = impl Copy;
+    let y: T = x;
+    match y {
+        _ => {} //~ ERROR unreachable
+    }
+}
+
+// This one caused ICE https://github.com/rust-lang/rust/issues/117100.
+fn inner_tuple() {
+    type T = impl Copy;
+    let foo: T = Some((1u32, 2u32));
+    match foo {
+        _ => {}
+        Some((a, b)) => {} //~ ERROR unreachable
+    }
+}
+
+type U = impl Copy;
+fn unify_never(x: Void, u: U) -> U {
+    if false {
+        match u {
+            _ => {} //~ ERROR unreachable
+        }
+    }
+    x
+}
+
+type V = impl Copy;
+fn infer_in_match(x: Option<V>) {
+    match x {
+        None => {}
+        Some((a, b)) => {}
+        Some((mut x, mut y)) => {
+            //~^ ERROR unreachable
+            x = 42;
+            y = "foo";
+        }
+    }
+}
+
+type W = impl Copy;
+#[derive(Copy, Clone)]
+struct Rec<'a> {
+    n: u32,
+    w: Option<&'a W>,
+}
+fn recursive_opaque() -> W {
+    if false {
+        match recursive_opaque() {
+            // Check for the ol' ICE when the type is recursively opaque.
+            _ => {}
+            Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} //~ ERROR unreachable
+        }
+    }
+    let w: Option<&'static W> = None;
+    Rec { n: 0, w }
+}
+
+type X = impl Copy;
+struct SecretelyVoid(X);
+fn nested_empty_opaque(x: Void) -> X {
+    if false {
+        let opaque_void = nested_empty_opaque(x);
+        let secretely_void = SecretelyVoid(opaque_void);
+        match secretely_void {
+            // FIXME: Unreachable not detected because `is_uninhabited` does not look into opaque
+            // types.
+            _ => {}
+        }
+    }
+    x
+}
diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr
new file mode 100644
index 00000000000..df6d43dbb3f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/impl-trait.stderr
@@ -0,0 +1,101 @@
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:17:13
+   |
+LL |             _ => {}
+   |             ^
+   |
+note: the lint level is defined here
+  --> $DIR/impl-trait.rs:5:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:31:13
+   |
+LL |             _ => {}
+   |             ^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:45:13
+   |
+LL |             Some(_) => {}
+   |             ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:61:13
+   |
+LL |             Some(_) => {}
+   |             ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:65:13
+   |
+LL |             _ => {}
+   |             ^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:78:9
+   |
+LL |         _ => {}
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:88:9
+   |
+LL |         _ => {}
+   |         - matches any value
+LL |         Some((a, b)) => {}
+   |         ^^^^^^^^^^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:96:13
+   |
+LL |             _ => {}
+   |             ^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:107:9
+   |
+LL |         Some((mut x, mut y)) => {
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/impl-trait.rs:126:13
+   |
+LL |             _ => {}
+   |             - matches any value
+LL |             Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
+
+error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
+  --> $DIR/impl-trait.rs:23:11
+   |
+LL |     match return_never_rpit(x) {}
+   |           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `impl Copy`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match return_never_rpit(x) {
+LL +         _ => todo!(),
+LL +     }
+   |
+
+error[E0004]: non-exhaustive patterns: type `T` is non-empty
+  --> $DIR/impl-trait.rs:37:11
+   |
+LL |     match return_never_tait(x) {}
+   |           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match return_never_tait(x) {
+LL +         _ => todo!(),
+LL +     }
+   |
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.