about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/token.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs29
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_borrowck/src/lib.rs8
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs103
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs11
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs478
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_hir/src/def.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs14
-rw-r--r--compiler/rustc_lexer/src/tests.rs8
-rw-r--r--compiler/rustc_llvm/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs42
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs20
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs39
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs47
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs29
-rw-r--r--compiler/rustc_middle/src/ty/util.rs9
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs4
-rw-r--r--compiler/rustc_passes/src/region.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs6
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs8
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/config.rs63
-rw-r--r--compiler/rustc_session/src/cstore.rs6
-rw-r--r--compiler/rustc_session/src/utils.rs20
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs76
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs9
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs15
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs6
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs2
56 files changed, 693 insertions, 508 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f5c4affdce2..75ccbc92be1 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1616,7 +1616,7 @@ pub enum StrStyle {
     /// A raw string, like `r##"foo"##`.
     ///
     /// The value is the number of `#` symbols used.
-    Raw(u16),
+    Raw(u8),
 }
 
 /// An AST literal.
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 7df385873c1..2132cdfc001 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -59,9 +59,9 @@ pub enum LitKind {
     Integer,
     Float,
     Str,
-    StrRaw(u16), // raw string delimited by `n` hash symbols
+    StrRaw(u8), // raw string delimited by `n` hash symbols
     ByteStr,
-    ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols
+    ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
     Err,
 }
 
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index d64f1a05712..9442e0f1a1f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -618,9 +618,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// Desugar `<expr>.await` into:
     /// ```rust
     /// match ::std::future::IntoFuture::into_future(<expr>) {
-    ///     mut pinned => loop {
+    ///     mut __awaitee => loop {
     ///         match unsafe { ::std::future::Future::poll(
-    ///             <::std::pin::Pin>::new_unchecked(&mut pinned),
+    ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),
     ///             ::std::future::get_context(task_context),
     ///         ) } {
     ///             ::std::task::Poll::Ready(result) => break result,
@@ -657,21 +657,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let expr = self.lower_expr_mut(expr);
         let expr_hir_id = expr.hir_id;
 
-        let pinned_ident = Ident::with_dummy_span(sym::pinned);
-        let (pinned_pat, pinned_pat_hid) =
-            self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable);
+        // Note that the name of this binding must not be changed to something else because
+        // debuggers and debugger extensions expect it to be called `__awaitee`. They use
+        // this name to identify what is being awaited by a suspended async functions.
+        let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
+        let (awaitee_pat, awaitee_pat_hid) =
+            self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
 
         let task_context_ident = Ident::with_dummy_span(sym::_task_context);
 
         // unsafe {
         //     ::std::future::Future::poll(
-        //         ::std::pin::Pin::new_unchecked(&mut pinned),
+        //         ::std::pin::Pin::new_unchecked(&mut __awaitee),
         //         ::std::future::get_context(task_context),
         //     )
         // }
         let poll_expr = {
-            let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid);
-            let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
+            let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);
+            let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);
             let task_context = if let Some(task_context_hid) = self.task_context {
                 self.expr_ident_mut(span, task_context_ident, task_context_hid)
             } else {
@@ -681,7 +684,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let new_unchecked = self.expr_call_lang_item_fn_mut(
                 span,
                 hir::LangItem::PinNewUnchecked,
-                arena_vec![self; ref_mut_pinned],
+                arena_vec![self; ref_mut_awaitee],
                 Some(expr_hir_id),
             );
             let get_context = self.expr_call_lang_item_fn_mut(
@@ -782,8 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             span: self.lower_span(span),
         });
 
-        // mut pinned => loop { ... }
-        let pinned_arm = self.arm(pinned_pat, loop_expr);
+        // mut __awaitee => loop { ... }
+        let awaitee_arm = self.arm(awaitee_pat, loop_expr);
 
         // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
         let into_future_span = self.mark_span_with_reason(
@@ -799,11 +802,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
         );
 
         // match <into_future_expr> {
-        //     mut pinned => loop { .. }
+        //     mut __awaitee => loop { .. }
         // }
         hir::ExprKind::Match(
             into_future_expr,
-            arena_vec![self; pinned_arm],
+            arena_vec![self; awaitee_arm],
             hir::MatchSource::AwaitDesugar,
         )
     }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 5b6147c7223..a778d8c5470 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -387,13 +387,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         if attr.has_name(sym::link) {
             for nested_meta in attr.meta_item_list().unwrap_or_default() {
                 if nested_meta.has_name(sym::modifiers) {
-                    gate_feature_post!(
-                        self,
-                        native_link_modifiers,
-                        nested_meta.span(),
-                        "native link modifiers are experimental"
-                    );
-
                     if let Some(modifiers) = nested_meta.value_str() {
                         for modifier in modifiers.as_str().split(',') {
                             if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
@@ -412,7 +405,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                                 gate_modifier!(
                                     "bundle" => native_link_modifiers_bundle
                                     "verbatim" => native_link_modifiers_verbatim
-                                    "whole-archive" => native_link_modifiers_whole_archive
                                     "as-needed" => native_link_modifiers_as_needed
                                 );
                             }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a8fd5bb50a6..0007d8026e6 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -156,7 +156,6 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let tcx = infcx.tcx;
     let param_env = tcx.param_env(def.did);
-    let id = tcx.hir().local_def_id_to_hir_id(def.did);
 
     let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
     for var_debug_info in &input_body.var_debug_info {
@@ -226,7 +225,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         .iterate_to_fixpoint()
         .into_results_cursor(&body);
 
-    let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure();
+    let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def.did).is_fn_or_closure();
     let borrow_set =
         Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
 
@@ -289,8 +288,9 @@ fn do_mir_borrowck<'a, 'tcx>(
         .pass_name("borrowck")
         .iterate_to_fixpoint();
 
+    let def_hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
     let movable_generator = !matches!(
-        tcx.hir().get(id),
+        tcx.hir().get(def_hir_id),
         Node::Expr(&hir::Expr {
             kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)),
             ..
@@ -385,7 +385,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         let scope = mbcx.body.source_info(location).scope;
         let lint_root = match &mbcx.body.source_scopes[scope].local_data {
             ClearCrossCrate::Set(data) => data.lint_root,
-            _ => id,
+            _ => def_hir_id,
         };
 
         // Span and message don't matter; we overwrite them below anyway
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index e9c64049817..0bf2eb17d1b 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
-        match tcx.hir().body_owner_kind(self.mir_hir_id) {
+        match tcx.hir().body_owner_kind(self.mir_def.did) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
                 let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
                     tcx.type_of(typeck_root_def_id)
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index dbbbbd5ecc0..548ae0e411d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1844,7 +1844,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // This change is somewhat breaking in practice due to local static libraries being linked
     // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
     if sess.opts.debugging_opts.link_native_libraries {
-        add_local_native_libraries(cmd, sess, codegen_results);
+        add_local_native_libraries(cmd, sess, codegen_results, crate_type);
     }
 
     // Upstream rust libraries and their nobundle static libraries
@@ -2016,6 +2016,16 @@ fn add_order_independent_options(
     add_rpath_args(cmd, sess, codegen_results, out_filename);
 }
 
+// A dylib may reexport symbols from the linked rlib or native static library.
+// Even if some symbol is reexported it's still not necessarily counted as used and may be
+// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static
+// libraries as whole-archive to avoid losing reexported symbols.
+// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive.
+fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool {
+    crate_type == CrateType::Dylib
+        && !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol())
+}
+
 /// # Native library linking
 ///
 /// User-supplied library search paths (-L on the command line). These are the same paths used to
@@ -2029,6 +2039,7 @@ fn add_local_native_libraries(
     cmd: &mut dyn Linker,
     sess: &Session,
     codegen_results: &CodegenResults,
+    crate_type: CrateType,
 ) {
     let filesearch = sess.target_filesearch(PathKind::All);
     for search_path in filesearch.search_paths() {
@@ -2046,14 +2057,18 @@ fn add_local_native_libraries(
         codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
 
     let search_path = OnceCell::new();
-    let mut last = (NativeLibKind::Unspecified, None);
+    let mut last = (None, NativeLibKind::Unspecified, None);
     for lib in relevant_libs {
         let Some(name) = lib.name else {
             continue;
         };
 
         // Skip if this library is the same as the last.
-        last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+        last = if (lib.name, lib.kind, lib.verbatim) == last {
+            continue;
+        } else {
+            (lib.name, lib.kind, lib.verbatim)
+        };
 
         let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
@@ -2064,15 +2079,19 @@ fn add_local_native_libraries(
             NativeLibKind::Framework { as_needed } => {
                 cmd.link_framework(name, as_needed.unwrap_or(true))
             }
-            NativeLibKind::Static { bundle: None | Some(true), .. }
-            | NativeLibKind::Static { whole_archive: Some(true), .. } => {
-                cmd.link_whole_staticlib(
-                    name,
-                    verbatim,
-                    &search_path.get_or_init(|| archive_search_paths(sess)),
-                );
+            NativeLibKind::Static { whole_archive, .. } => {
+                if whole_archive == Some(true)
+                    || (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd))
+                {
+                    cmd.link_whole_staticlib(
+                        name,
+                        verbatim,
+                        &search_path.get_or_init(|| archive_search_paths(sess)),
+                    );
+                } else {
+                    cmd.link_staticlib(name, verbatim)
+                }
             }
-            NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
             NativeLibKind::RawDylib => {
                 // FIXME(#58713): Proper handling for raw dylibs.
                 bug!("raw_dylib feature not yet implemented");
@@ -2197,34 +2216,37 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                 // external build system already has the native dependencies defined, and it
                 // will provide them to the linker itself.
                 if sess.opts.debugging_opts.link_native_libraries {
-                    let mut last = None;
+                    let mut last = (None, NativeLibKind::Unspecified, None);
                     for lib in &codegen_results.crate_info.native_libraries[&cnum] {
+                        let Some(name) = lib.name else {
+                            continue;
+                        };
                         if !relevant_lib(sess, lib) {
-                            // Skip libraries if they are disabled by `#[link(cfg=...)]`
                             continue;
                         }
 
                         // Skip if this library is the same as the last.
-                        if last == lib.name {
+                        last = if (lib.name, lib.kind, lib.verbatim) == last {
                             continue;
-                        }
-
-                        if let Some(static_lib_name) = lib.name {
-                            if let NativeLibKind::Static { bundle: Some(false), whole_archive } =
-                                lib.kind
+                        } else {
+                            (lib.name, lib.kind, lib.verbatim)
+                        };
+
+                        if let NativeLibKind::Static { bundle: Some(false), whole_archive } =
+                            lib.kind
+                        {
+                            let verbatim = lib.verbatim.unwrap_or(false);
+                            if whole_archive == Some(true)
+                                || (whole_archive == None
+                                    && default_to_whole_archive(sess, crate_type, cmd))
                             {
-                                let verbatim = lib.verbatim.unwrap_or(false);
-                                if whole_archive == Some(true) {
-                                    cmd.link_whole_staticlib(
-                                        static_lib_name,
-                                        verbatim,
-                                        search_path.get_or_init(|| archive_search_paths(sess)),
-                                    );
-                                } else {
-                                    cmd.link_staticlib(static_lib_name, verbatim);
-                                }
-
-                                last = lib.name;
+                                cmd.link_whole_staticlib(
+                                    name,
+                                    verbatim,
+                                    search_path.get_or_init(|| archive_search_paths(sess)),
+                                );
+                            } else {
+                                cmd.link_staticlib(name, verbatim);
                             }
                         }
                     }
@@ -2282,15 +2304,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         let cratepath = &src.rlib.as_ref().unwrap().0;
 
         let mut link_upstream = |path: &Path| {
-            // If we're creating a dylib, then we need to include the
-            // whole of each object in our archive into that artifact. This is
-            // because a `dylib` can be reused as an intermediate artifact.
-            //
-            // Note, though, that we don't want to include the whole of a
-            // compiler-builtins crate (e.g., compiler-rt) because it'll get
-            // repeatedly linked anyway.
+            // We don't want to include the whole compiler-builtins crate (e.g., compiler-rt)
+            // regardless of the default because it'll get repeatedly linked anyway.
             let path = fix_windows_verbatim_for_gcc(path);
-            if crate_type == CrateType::Dylib
+            if default_to_whole_archive(sess, crate_type, cmd)
                 && codegen_results.crate_info.compiler_builtins != Some(cnum)
             {
                 cmd.link_whole_rlib(&path);
@@ -2401,7 +2418,7 @@ fn add_upstream_native_libraries(
     sess: &Session,
     codegen_results: &CodegenResults,
 ) {
-    let mut last = (NativeLibKind::Unspecified, None);
+    let mut last = (None, NativeLibKind::Unspecified, None);
     for &cnum in &codegen_results.crate_info.used_crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
             let Some(name) = lib.name else {
@@ -2412,7 +2429,11 @@ fn add_upstream_native_libraries(
             }
 
             // Skip if this library is the same as the last.
-            last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+            last = if (lib.name, lib.kind, lib.verbatim) == last {
+                continue;
+            } else {
+                (lib.name, lib.kind, lib.verbatim)
+            };
 
             let verbatim = lib.verbatim.unwrap_or(false);
             match lib.kind {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index a838787381d..3a66bfafaf3 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -186,6 +186,9 @@ pub trait Linker {
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
+    fn exported_symbol_means_used_symbol(&self) -> bool {
+        true
+    }
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
     fn group_end(&mut self);
@@ -724,6 +727,10 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
+    fn exported_symbol_means_used_symbol(&self) -> bool {
+        self.sess.target.is_like_windows || self.sess.target.is_like_osx
+    }
+
     fn subsystem(&mut self, subsystem: &str) {
         self.linker_arg("--subsystem");
         self.linker_arg(&subsystem);
@@ -1471,6 +1478,10 @@ impl<'a> Linker for L4Bender<'a> {
         return;
     }
 
+    fn exported_symbol_means_used_symbol(&self) -> bool {
+        false
+    }
+
     fn subsystem(&mut self, subsystem: &str) {
         self.cmd.arg(&format!("--subsystem {}", subsystem));
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index df809e82701..946546263ea 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -38,7 +38,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             || matches!(
                 ecx.tcx.def_kind(cid.instance.def_id()),
                 DefKind::Const
-                    | DefKind::Static
+                    | DefKind::Static(_)
                     | DefKind::ConstParam
                     | DefKind::AnonConst
                     | DefKind::InlineConst
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 5a6a2b2c57b..18302ffdb8e 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -6,7 +6,7 @@
 //!
 //! (In order to prevent the pathological case, we'd need to lazily construct the resulting
 //! `NamedMatch`es at the very end. It'd be a pain, and require more memory to keep around old
-//! items, but it would also save overhead)
+//! matcher positions, but it would also save overhead)
 //!
 //! We don't say this parser uses the Earley algorithm, because it's unnecessarily inaccurate.
 //! The macro parser restricts itself to the features of finite state automata. Earley parsers
@@ -14,19 +14,19 @@
 //!
 //! Quick intro to how the parser works:
 //!
-//! A 'position' is a dot in the middle of a matcher, usually represented as a
-//! dot. For example `· a $( a )* a b` is a position, as is `a $( · a )* a b`.
+//! A "matcher position" (a.k.a. "position" or "mp") is a dot in the middle of a matcher, usually
+//! written as a `·`. For example `· a $( a )* a b` is one, as is `a $( · a )* a b`.
 //!
 //! The parser walks through the input a character at a time, maintaining a list
-//! of threads consistent with the current position in the input string: `cur_items`.
+//! of threads consistent with the current position in the input string: `cur_mps`.
 //!
-//! As it processes them, it fills up `eof_items` with threads that would be valid if
-//! the macro invocation is now over, `bb_items` with threads that are waiting on
-//! a Rust non-terminal like `$e:expr`, and `next_items` with threads that are waiting
+//! As it processes them, it fills up `eof_mps` with threads that would be valid if
+//! the macro invocation is now over, `bb_mps` with threads that are waiting on
+//! a Rust non-terminal like `$e:expr`, and `next_mps` with threads that are waiting
 //! on a particular token. Most of the logic concerns moving the · through the
 //! repetitions indicated by Kleene stars. The rules for moving the · without
 //! consuming any input are called epsilon transitions. It only advances or calls
-//! out to the real Rust parser when no `cur_items` threads remain.
+//! out to the real Rust parser when no `cur_mps` threads remain.
 //!
 //! Example:
 //!
@@ -40,28 +40,28 @@
 //!
 //! Remaining input: a a a b
 //! cur: [a · $( a )* a b]
-//! Descend/Skip (first item).
+//! Descend/Skip (first position).
 //! next: [a $( · a )* a b]  [a $( a )* · a b].
 //!
 //! - - - Advance over an a. - - -
 //!
 //! Remaining input: a a b
 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
-//! Follow epsilon transition: Finish/Repeat (first item)
+//! Follow epsilon transition: Finish/Repeat (first position)
 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 //!
 //! - - - Advance over an a. - - - (this looks exactly like the last step)
 //!
 //! Remaining input: a b
 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
-//! Follow epsilon transition: Finish/Repeat (first item)
+//! Follow epsilon transition: Finish/Repeat (first position)
 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 //!
 //! - - - Advance over an a. - - - (this looks exactly like the last step)
 //!
 //! Remaining input: b
 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
-//! Follow epsilon transition: Finish/Repeat (first item)
+//! Follow epsilon transition: Finish/Repeat (first position)
 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 //!
 //! - - - Advance over a b. - - -
@@ -89,15 +89,13 @@ use std::borrow::Cow;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::mem;
 
-/// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
-///
 /// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have
 /// descended into.
 #[derive(Clone)]
-struct MatcherTtFrame<'tt> {
-    /// The "parent" matcher that we are descending into.
-    elts: &'tt [TokenTree],
-    /// The position of the "dot" in `elts` at the time we descended.
+struct MatcherPosFrame<'tt> {
+    /// The "parent" matcher that we have descended from.
+    tts: &'tt [TokenTree],
+    /// The position of the "dot" in `tt` at the time we descended.
     idx: usize,
 }
 
@@ -110,128 +108,135 @@ type NamedMatchVec = SmallVec<[NamedMatch; 1]>;
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(NamedMatchVec, 48);
 
-/// Represents a single "position" (aka "matcher position", aka "item"), as
-/// described in the module documentation.
+/// A single matcher position, which could be within the top-level matcher, a submatcher, a
+/// subsubmatcher, etc. For example:
+/// ```text
+/// macro_rules! m { $id:ident ( $($e:expr),* ) } => { ... }
+///                              <---------->     second submatcher; one tt, one metavar
+///                            <-------------->   first submatcher; three tts, zero metavars
+///                  <--------------------------> top-level matcher; two tts, one metavar
+/// ```
 #[derive(Clone)]
 struct MatcherPos<'tt> {
-    /// The token or slice of tokens that make up the matcher. `elts` is short for "elements".
-    top_elts: &'tt [TokenTree],
+    /// The tokens that make up the current matcher. When we are within a `Sequence` or `Delimited`
+    /// submatcher, this is just the contents of that submatcher.
+    tts: &'tt [TokenTree],
 
-    /// The position of the "dot" in this matcher
+    /// The "dot" position within the current submatcher, i.e. the index into `tts`.
     idx: usize,
 
-    /// For each named metavar in the matcher, we keep track of token trees matched against the
-    /// metavar by the black box parser. In particular, there may be more than one match per
-    /// metavar if we are in a repetition (each repetition matches each of the variables).
-    /// Moreover, matchers and repetitions can be nested; the `matches` field is shared (hence the
-    /// `Rc`) among all "nested" matchers. `match_lo`, `match_cur`, and `match_hi` keep track of
-    /// the current position of the `self` matcher position in the shared `matches` list.
-    ///
-    /// Also, note that while we are descending into a sequence, matchers are given their own
-    /// `matches` vector. Only once we reach the end of a full repetition of the sequence do we add
-    /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep`
-    /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one
-    /// wants the shared `matches`, one should use `up.matches`.
-    matches: Box<[Lrc<NamedMatchVec>]>,
-    /// The position in `matches` corresponding to the first metavar in this matcher's sequence of
-    /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds
-    /// to `matches[match_lo]`.
+    /// This vector ends up with one element per metavar in the *top-level* matcher, even when this
+    /// `MatcherPos` is for a submatcher. Each element records token trees matched against the
+    /// relevant metavar by the black box parser. The element will be a `MatchedSeq` if the
+    /// corresponding metavar is within a sequence.
+    matches: Lrc<NamedMatchVec>,
+
+    /// The number of sequences this mp is within.
+    seq_depth: usize,
+
+    /// The position in `matches` of the first metavar in this (sub)matcher. Zero if there are
+    /// no metavars.
     match_lo: usize,
-    /// The position in `matches` corresponding to the metavar we are currently trying to match
-    /// against the source token stream. `match_lo <= match_cur <= match_hi`.
+
+    /// The position in `matches` of the next metavar to be matched against the source token
+    /// stream. Should not be used if there are no metavars.
     match_cur: usize,
-    /// Similar to `match_lo` except `match_hi` is the position in `matches` of the _last_ metavar
-    /// in this matcher.
-    match_hi: usize,
 
-    /// This field is only used if we are matching a repetition.
-    repetition: Option<MatcherPosRepetition<'tt>>,
+    /// This field is only used if we are matching a sequence.
+    sequence: Option<MatcherPosSequence<'tt>>,
 
-    /// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
-    /// a delimited token tree (e.g., something wrapped in `(` `)`) or to get the contents of a doc
-    /// comment...
-    ///
-    /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. )
-    /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
-    /// that where the bottom of the stack is the outermost matcher.
-    /// Also, throughout the comments, this "descent" is often referred to as "unzipping"...
-    stack: SmallVec<[MatcherTtFrame<'tt>; 1]>,
+    /// When we are within a `Delimited` submatcher (or subsubmatcher), this tracks the parent
+    /// matcher(s). The bottom of the stack is the top-level matcher.
+    stack: SmallVec<[MatcherPosFrame<'tt>; 1]>,
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MatcherPos<'_>, 112);
+rustc_data_structures::static_assert_size!(MatcherPos<'_>, 104);
 
 impl<'tt> MatcherPos<'tt> {
-    /// `len` `Vec`s (initially shared and empty) that will store matches of metavars.
-    fn create_matches(len: usize) -> Box<[Lrc<NamedMatchVec>]> {
-        if len == 0 {
-            vec![]
-        } else {
-            let empty_matches = Lrc::new(SmallVec::new());
-            vec![empty_matches; len]
-        }
-        .into_boxed_slice()
-    }
-
-    /// Generates the top-level matcher position in which the "dot" is before the first token of
-    /// the matcher `ms`.
-    fn new(ms: &'tt [TokenTree]) -> Self {
-        let match_idx_hi = count_names(ms);
+    fn top_level(matcher: &'tt [TokenTree], empty_matches: Lrc<NamedMatchVec>) -> Self {
         MatcherPos {
-            // Start with the top level matcher given to us.
-            top_elts: ms,
-
-            // The "dot" is before the first token of the matcher.
+            tts: matcher,
             idx: 0,
-
-            // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in
-            // `top_elts`. `match_lo` for `top_elts` is 0 and `match_hi` is `match_idx_hi`.
-            // `match_cur` is 0 since we haven't actually matched anything yet.
-            matches: Self::create_matches(match_idx_hi),
+            matches: empty_matches,
+            seq_depth: 0,
             match_lo: 0,
             match_cur: 0,
-            match_hi: match_idx_hi,
-
-            // Haven't descended into any delimiters, so this is empty.
             stack: smallvec![],
-
-            // Haven't descended into any sequences, so this is `None`.
-            repetition: None,
+            sequence: None,
         }
     }
 
-    fn repetition(up: Box<MatcherPos<'tt>>, seq: &'tt SequenceRepetition) -> Self {
-        MatcherPos {
-            top_elts: &seq.tts,
+    fn sequence(
+        parent: Box<MatcherPos<'tt>>,
+        seq: &'tt SequenceRepetition,
+        empty_matches: Lrc<NamedMatchVec>,
+    ) -> Self {
+        let mut mp = MatcherPos {
+            tts: &seq.tts,
             idx: 0,
-            matches: Self::create_matches(up.matches.len()),
-            match_lo: up.match_cur,
-            match_cur: up.match_cur,
-            match_hi: up.match_cur + seq.num_captures,
-            repetition: Some(MatcherPosRepetition { up, seq }),
+            matches: parent.matches.clone(),
+            seq_depth: parent.seq_depth,
+            match_lo: parent.match_cur,
+            match_cur: parent.match_cur,
+            sequence: Some(MatcherPosSequence { parent, seq }),
             stack: smallvec![],
+        };
+        // Start with an empty vec for each metavar within the sequence. Note that `mp.seq_depth`
+        // must have the parent's depth at this point for these `push_match` calls to work.
+        for idx in mp.match_lo..mp.match_lo + seq.num_captures {
+            mp.push_match(idx, MatchedSeq(empty_matches.clone()));
         }
+        mp.seq_depth += 1;
+        mp
     }
 
     /// Adds `m` as a named match for the `idx`-th metavar.
     fn push_match(&mut self, idx: usize, m: NamedMatch) {
-        let matches = Lrc::make_mut(&mut self.matches[idx]);
-        matches.push(m);
+        let matches = Lrc::make_mut(&mut self.matches);
+        match self.seq_depth {
+            0 => {
+                // We are not within a sequence. Just append `m`.
+                assert_eq!(idx, matches.len());
+                matches.push(m);
+            }
+            _ => {
+                // We are within a sequence. Find the final `MatchedSeq` at the appropriate depth
+                // and append `m` to its vector.
+                let mut curr = &mut matches[idx];
+                for _ in 0..self.seq_depth - 1 {
+                    match curr {
+                        MatchedSeq(seq) => {
+                            let seq = Lrc::make_mut(seq);
+                            curr = seq.last_mut().unwrap();
+                        }
+                        _ => unreachable!(),
+                    }
+                }
+                match curr {
+                    MatchedSeq(seq) => {
+                        let seq = Lrc::make_mut(seq);
+                        seq.push(m);
+                    }
+                    _ => unreachable!(),
+                }
+            }
+        }
     }
 }
 
 #[derive(Clone)]
-struct MatcherPosRepetition<'tt> {
-    /// The "parent" matcher position. That is, the matcher position just before we enter the
-    /// sequence.
-    up: Box<MatcherPos<'tt>>,
+struct MatcherPosSequence<'tt> {
+    /// The parent matcher position. Effectively gives a linked list of matches all the way to the
+    /// top-level matcher.
+    parent: Box<MatcherPos<'tt>>,
 
     /// The sequence itself.
     seq: &'tt SequenceRepetition,
 }
 
-enum EofItems<'tt> {
+enum EofMatcherPositions<'tt> {
     None,
     One(Box<MatcherPos<'tt>>),
     Multiple,
@@ -254,24 +259,24 @@ crate enum ParseResult<T> {
 /// of metavars to the token trees they bind to.
 crate type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
 
-/// Count how many metavars are named in the given matcher `ms`.
-pub(super) fn count_names(ms: &[TokenTree]) -> usize {
-    ms.iter().fold(0, |count, elt| {
-        count
-            + match elt {
-                TokenTree::Delimited(_, delim) => count_names(delim.inner_tts()),
+/// Count how many metavars declarations are in `matcher`.
+pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
+    matcher
+        .iter()
+        .map(|tt| {
+            match tt {
+                TokenTree::Delimited(_, delim) => count_metavar_decls(delim.inner_tts()),
                 TokenTree::MetaVar(..) => 0,
                 TokenTree::MetaVarDecl(..) => 1,
-                // Panicking here would abort execution because `parse_tree` makes use of this
-                // function. In other words, RHS meta-variable expressions eventually end-up here.
-                //
-                // `0` is still returned to inform that no meta-variable was found. `Meta-variables
-                // != Meta-variable expressions`
+                // RHS meta-variable expressions eventually end-up here. `0` is returned to inform
+                // that no meta-variable was found, because "meta-variables" != "meta-variable
+                // expressions".
                 TokenTree::MetaVarExpr(..) => 0,
                 TokenTree::Sequence(_, seq) => seq.num_captures,
                 TokenTree::Token(..) => 0,
             }
-    })
+        })
+        .sum()
 }
 
 /// `NamedMatch` is a pattern-match result for a single metavar. All
@@ -331,11 +336,9 @@ crate enum NamedMatch {
     MatchedNonterminal(Lrc<Nonterminal>),
 }
 
-/// Takes a slice of token trees `ms` representing a matcher which successfully matched input
-/// and an iterator of items that matched input and produces a `NamedParseResult`.
 fn nameize<I: Iterator<Item = NamedMatch>>(
     sess: &ParseSess,
-    ms: &[TokenTree],
+    matcher: &[TokenTree],
     mut res: I,
 ) -> NamedParseResult {
     // Recursively descend into each type of matcher (e.g., sequences, delimited, metavars) and make
@@ -344,11 +347,11 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
     // `NamedParseResult`.
     fn n_rec<I: Iterator<Item = NamedMatch>>(
         sess: &ParseSess,
-        m: &TokenTree,
+        tt: &TokenTree,
         res: &mut I,
         ret_val: &mut FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
     ) -> Result<(), (rustc_span::Span, String)> {
-        match *m {
+        match *tt {
             TokenTree::Sequence(_, ref seq) => {
                 for next_m in &seq.tts {
                     n_rec(sess, next_m, res.by_ref(), ret_val)?
@@ -380,8 +383,8 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
     }
 
     let mut ret_val = FxHashMap::default();
-    for m in ms {
-        match n_rec(sess, m, res.by_ref(), &mut ret_val) {
+    for tt in matcher {
+        match n_rec(sess, tt, res.by_ref(), &mut ret_val) {
             Ok(_) => {}
             Err((sp, msg)) => return Error(sp, msg),
         }
@@ -401,86 +404,96 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
     }
 }
 
-// Note: the item vectors could be created and dropped within `parse_tt`, but to avoid excess
+// Note: the position vectors could be created and dropped within `parse_tt`, but to avoid excess
 // allocations we have a single vector fo each kind that is cleared and reused repeatedly.
 pub struct TtParser<'tt> {
     macro_name: Ident,
 
-    /// The set of current items to be processed. This should be empty by the end of a successful
+    /// The set of current mps to be processed. This should be empty by the end of a successful
     /// execution of `parse_tt_inner`.
-    cur_items: Vec<Box<MatcherPos<'tt>>>,
+    cur_mps: Vec<Box<MatcherPos<'tt>>>,
 
-    /// The set of newly generated items. These are used to replenish `cur_items` in the function
+    /// The set of newly generated mps. These are used to replenish `cur_mps` in the function
     /// `parse_tt`.
-    next_items: Vec<Box<MatcherPos<'tt>>>,
+    next_mps: Vec<Box<MatcherPos<'tt>>>,
 
-    /// The set of items that are waiting for the black-box parser.
-    bb_items: Vec<Box<MatcherPos<'tt>>>,
+    /// The set of mps that are waiting for the black-box parser.
+    bb_mps: Vec<Box<MatcherPos<'tt>>>,
+
+    /// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
+    /// that have no metavars.
+    empty_matches: Lrc<NamedMatchVec>,
 }
 
 impl<'tt> TtParser<'tt> {
     pub(super) fn new(macro_name: Ident) -> TtParser<'tt> {
-        TtParser { macro_name, cur_items: vec![], next_items: vec![], bb_items: vec![] }
+        TtParser {
+            macro_name,
+            cur_mps: vec![],
+            next_mps: vec![],
+            bb_mps: vec![],
+            empty_matches: Lrc::new(smallvec![]),
+        }
     }
 
-    /// Process the matcher positions of `cur_items` until it is empty. In the process, this will
-    /// produce more items in `next_items` and `bb_items`.
-    ///
-    /// For more info about the how this happens, see the module-level doc comments and the inline
-    /// comments of this function.
+    /// Process the matcher positions of `cur_mps` until it is empty. In the process, this will
+    /// produce more mps in `next_mps` and `bb_mps`.
     ///
     /// # Returns
     ///
     /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
-    /// track of through the items generated.
+    /// track of through the mps generated.
     fn parse_tt_inner(
         &mut self,
         sess: &ParseSess,
-        ms: &[TokenTree],
+        matcher: &[TokenTree],
         token: &Token,
     ) -> Option<NamedParseResult> {
         // Matcher positions that would be valid if the macro invocation was over now. Only
         // modified if `token == Eof`.
-        let mut eof_items = EofItems::None;
-
-        while let Some(mut item) = self.cur_items.pop() {
-            // When unzipped trees end, remove them. This corresponds to backtracking out of a
-            // delimited submatcher into which we already descended. When backtracking out again, we
-            // need to advance the "dot" past the delimiters in the outer matcher.
-            while item.idx >= item.top_elts.len() {
-                match item.stack.pop() {
-                    Some(MatcherTtFrame { elts, idx }) => {
-                        item.top_elts = elts;
-                        item.idx = idx + 1;
+        let mut eof_mps = EofMatcherPositions::None;
+
+        while let Some(mut mp) = self.cur_mps.pop() {
+            // Backtrack out of delimited submatcher when necessary. When backtracking out again,
+            // we need to advance the "dot" past the delimiters in the parent matcher(s).
+            while mp.idx >= mp.tts.len() {
+                match mp.stack.pop() {
+                    Some(MatcherPosFrame { tts, idx }) => {
+                        mp.tts = tts;
+                        mp.idx = idx + 1;
                     }
                     None => break,
                 }
             }
 
-            // Get the current position of the "dot" (`idx`) in `item` and the number of token
+            // Get the current position of the "dot" (`idx`) in `mp` and the number of token
             // trees in the matcher (`len`).
-            let idx = item.idx;
-            let len = item.top_elts.len();
+            let idx = mp.idx;
+            let len = mp.tts.len();
 
             if idx < len {
                 // We are in the middle of a matcher. Compare the matcher's current tt against
                 // `token`.
-                match &item.top_elts[idx] {
+                match &mp.tts[idx] {
                     TokenTree::Sequence(_sp, seq) => {
                         let op = seq.kleene.op;
                         if op == mbe::KleeneOp::ZeroOrMore || op == mbe::KleeneOp::ZeroOrOne {
                             // Allow for the possibility of zero matches of this sequence.
-                            let mut new_item = item.clone();
-                            new_item.match_cur += seq.num_captures;
-                            new_item.idx += 1;
-                            for idx in item.match_cur..item.match_cur + seq.num_captures {
-                                new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![])));
+                            let mut new_mp = mp.clone();
+                            new_mp.match_cur += seq.num_captures;
+                            new_mp.idx += 1;
+                            for idx in mp.match_cur..mp.match_cur + seq.num_captures {
+                                new_mp.push_match(idx, MatchedSeq(self.empty_matches.clone()));
                             }
-                            self.cur_items.push(new_item);
+                            self.cur_mps.push(new_mp);
                         }
 
                         // Allow for the possibility of one or more matches of this sequence.
-                        self.cur_items.push(box MatcherPos::repetition(item, &seq));
+                        self.cur_mps.push(box MatcherPos::sequence(
+                            mp,
+                            &seq,
+                            self.empty_matches.clone(),
+                        ));
                     }
 
                     &TokenTree::MetaVarDecl(span, _, None) => {
@@ -497,61 +510,63 @@ impl<'tt> TtParser<'tt> {
                         // We use the span of the metavariable declaration to determine any
                         // edition-specific matching behavior for non-terminals.
                         if Parser::nonterminal_may_begin_with(kind, token) {
-                            self.bb_items.push(item);
+                            self.bb_mps.push(mp);
                         }
                     }
 
                     TokenTree::Delimited(_, delimited) => {
                         // To descend into a delimited submatcher, we push the current matcher onto
-                        // a stack and push a new item containing the submatcher onto `cur_items`.
+                        // a stack and push a new mp containing the submatcher onto `cur_mps`.
                         //
                         // At the beginning of the loop, if we reach the end of the delimited
                         // submatcher, we pop the stack to backtrack out of the descent. Note that
                         // we use `all_tts` to include the open and close delimiter tokens.
-                        let lower_elts = mem::replace(&mut item.top_elts, &delimited.all_tts);
-                        let idx = item.idx;
-                        item.stack.push(MatcherTtFrame { elts: lower_elts, idx });
-                        item.idx = 0;
-                        self.cur_items.push(item);
+                        let tts = mem::replace(&mut mp.tts, &delimited.all_tts);
+                        let idx = mp.idx;
+                        mp.stack.push(MatcherPosFrame { tts, idx });
+                        mp.idx = 0;
+                        self.cur_mps.push(mp);
                     }
 
                     TokenTree::Token(t) => {
                         // If it's a doc comment, we just ignore it and move on to the next tt in
-                        // the matcher. If the token matches, we can just advance the parser.
+                        // the matcher. This is a bug, but #95267 showed that existing programs
+                        // rely on this behaviour, and changing it would require some care and a
+                        // transition period.
+                        //
+                        // If the token matches, we can just advance the parser.
+                        //
                         // Otherwise, this match has failed, there is nothing to do, and hopefully
-                        // another item in `cur_items` will match.
+                        // another mp in `cur_mps` will match.
                         if matches!(t, Token { kind: DocComment(..), .. }) {
-                            item.idx += 1;
-                            self.cur_items.push(item);
+                            mp.idx += 1;
+                            self.cur_mps.push(mp);
                         } else if token_name_eq(&t, token) {
-                            item.idx += 1;
-                            self.next_items.push(item);
+                            mp.idx += 1;
+                            self.next_mps.push(mp);
                         }
                     }
 
                     // These cannot appear in a matcher.
                     TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
                 }
-            } else if let Some(repetition) = &item.repetition {
-                // We are past the end of a repetition.
+            } else if let Some(sequence) = &mp.sequence {
+                // We are past the end of a sequence.
                 debug_assert!(idx <= len + 1);
 
                 if idx == len {
-                    // Add all matches from the sequence to `up`, and move the "dot" past the
-                    // repetition in `up`. This allows for the case where the sequence matching is
-                    // finished.
-                    let mut new_pos = repetition.up.clone();
-                    for idx in item.match_lo..item.match_hi {
-                        let sub = item.matches[idx].clone();
-                        new_pos.push_match(idx, MatchedSeq(sub));
-                    }
-                    new_pos.match_cur = item.match_hi;
-                    new_pos.idx += 1;
-                    self.cur_items.push(new_pos);
+                    // Add all matches from the sequence to `parent`, and move the "dot" past the
+                    // sequence in `parent`. This allows for the case where the sequence matching
+                    // is finished.
+                    let mut new_mp = sequence.parent.clone();
+                    new_mp.matches = mp.matches.clone();
+                    new_mp.match_cur = mp.match_lo + sequence.seq.num_captures;
+                    new_mp.idx += 1;
+                    self.cur_mps.push(new_mp);
                 }
 
-                if idx == len && repetition.seq.separator.is_some() {
-                    if repetition
+                if idx == len && sequence.seq.separator.is_some() {
+                    if sequence
                         .seq
                         .separator
                         .as_ref()
@@ -559,25 +574,27 @@ impl<'tt> TtParser<'tt> {
                     {
                         // The matcher has a separator, and it matches the current token. We can
                         // advance past the separator token.
-                        item.idx += 1;
-                        self.next_items.push(item);
+                        mp.idx += 1;
+                        self.next_mps.push(mp);
                     }
-                } else if repetition.seq.kleene.op != mbe::KleeneOp::ZeroOrOne {
+                } else if sequence.seq.kleene.op != mbe::KleeneOp::ZeroOrOne {
                     // We don't need a separator. Move the "dot" back to the beginning of the
                     // matcher and try to match again UNLESS we are only allowed to have _one_
                     // repetition.
-                    item.match_cur = item.match_lo;
-                    item.idx = 0;
-                    self.cur_items.push(item);
+                    mp.match_cur = mp.match_lo;
+                    mp.idx = 0;
+                    self.cur_mps.push(mp);
                 }
             } else {
-                // We are past the end of the matcher, and not in a repetition. Look for end of
+                // We are past the end of the matcher, and not in a sequence. Look for end of
                 // input.
                 debug_assert_eq!(idx, len);
                 if *token == token::Eof {
-                    eof_items = match eof_items {
-                        EofItems::None => EofItems::One(item),
-                        EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
+                    eof_mps = match eof_mps {
+                        EofMatcherPositions::None => EofMatcherPositions::One(mp),
+                        EofMatcherPositions::One(_) | EofMatcherPositions::Multiple => {
+                            EofMatcherPositions::Multiple
+                        }
                     }
                 }
             }
@@ -586,16 +603,18 @@ impl<'tt> TtParser<'tt> {
         // If we reached the end of input, check that there is EXACTLY ONE possible matcher.
         // Otherwise, either the parse is ambiguous (which is an error) or there is a syntax error.
         if *token == token::Eof {
-            Some(match eof_items {
-                EofItems::One(mut eof_item) => {
-                    let matches =
-                        eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
-                    nameize(sess, ms, matches)
+            Some(match eof_mps {
+                EofMatcherPositions::One(mut eof_mp) => {
+                    assert_eq!(eof_mp.matches.len(), count_metavar_decls(matcher));
+                    // Need to take ownership of the matches from within the `Lrc`.
+                    Lrc::make_mut(&mut eof_mp.matches);
+                    let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
+                    nameize(sess, matcher, matches)
                 }
-                EofItems::Multiple => {
+                EofMatcherPositions::Multiple => {
                     Error(token.span, "ambiguity: multiple successful parses".to_string())
                 }
-                EofItems::None => Failure(
+                EofMatcherPositions::None => Failure(
                     Token::new(
                         token::Eof,
                         if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
@@ -608,36 +627,35 @@ impl<'tt> TtParser<'tt> {
         }
     }
 
-    /// Use the given slice of token trees (`ms`) as a matcher. Match the token stream from the
-    /// given `parser` against it and return the match.
+    /// Match the token stream from `parser` against `matcher`.
     pub(super) fn parse_tt(
         &mut self,
         parser: &mut Cow<'_, Parser<'_>>,
-        ms: &'tt [TokenTree],
+        matcher: &'tt [TokenTree],
     ) -> NamedParseResult {
         // A queue of possible matcher positions. We initialize it with the matcher position in
-        // which the "dot" is before the first token of the first token tree in `ms`.
+        // which the "dot" is before the first token of the first token tree in `matcher`.
         // `parse_tt_inner` then processes all of these possible matcher positions and produces
-        // possible next positions into `next_items`. After some post-processing, the contents of
-        // `next_items` replenish `cur_items` and we start over again.
-        self.cur_items.clear();
-        self.cur_items.push(box MatcherPos::new(ms));
+        // possible next positions into `next_mps`. After some post-processing, the contents of
+        // `next_mps` replenish `cur_mps` and we start over again.
+        self.cur_mps.clear();
+        self.cur_mps.push(box MatcherPos::top_level(matcher, self.empty_matches.clone()));
 
         loop {
-            self.next_items.clear();
-            self.bb_items.clear();
+            self.next_mps.clear();
+            self.bb_mps.clear();
 
-            // Process `cur_items` until either we have finished the input or we need to get some
+            // Process `cur_mps` until either we have finished the input or we need to get some
             // parsing from the black-box parser done.
-            if let Some(result) = self.parse_tt_inner(parser.sess, ms, &parser.token) {
+            if let Some(result) = self.parse_tt_inner(parser.sess, matcher, &parser.token) {
                 return result;
             }
 
-            // `parse_tt_inner` handled all cur_items, so it's empty.
-            assert!(self.cur_items.is_empty());
+            // `parse_tt_inner` handled all of `cur_mps`, so it's empty.
+            assert!(self.cur_mps.is_empty());
 
             // Error messages here could be improved with links to original rules.
-            match (self.next_items.len(), self.bb_items.len()) {
+            match (self.next_mps.len(), self.bb_mps.len()) {
                 (0, 0) => {
                     // There are no possible next positions AND we aren't waiting for the black-box
                     // parser: syntax error.
@@ -648,17 +666,17 @@ impl<'tt> TtParser<'tt> {
                 }
 
                 (_, 0) => {
-                    // Dump all possible `next_items` into `cur_items` for the next iteration. Then
+                    // Dump all possible `next_mps` into `cur_mps` for the next iteration. Then
                     // process the next token.
-                    self.cur_items.extend(self.next_items.drain(..));
+                    self.cur_mps.extend(self.next_mps.drain(..));
                     parser.to_mut().bump();
                 }
 
                 (0, 1) => {
                     // We need to call the black-box parser to get some nonterminal.
-                    let mut item = self.bb_items.pop().unwrap();
-                    if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts[item.idx] {
-                        let match_cur = item.match_cur;
+                    let mut mp = self.bb_mps.pop().unwrap();
+                    if let TokenTree::MetaVarDecl(span, _, Some(kind)) = mp.tts[mp.idx] {
+                        let match_cur = mp.match_cur;
                         // We use the span of the metavariable declaration to determine any
                         // edition-specific matching behavior for non-terminals.
                         let nt = match parser.to_mut().parse_nonterminal(kind) {
@@ -678,13 +696,13 @@ impl<'tt> TtParser<'tt> {
                             NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
                             NtOrTt::Tt(tt) => MatchedTokenTree(tt),
                         };
-                        item.push_match(match_cur, m);
-                        item.idx += 1;
-                        item.match_cur += 1;
+                        mp.push_match(match_cur, m);
+                        mp.idx += 1;
+                        mp.match_cur += 1;
                     } else {
                         unreachable!()
                     }
-                    self.cur_items.push(item);
+                    self.cur_mps.push(mp);
                 }
 
                 (_, _) => {
@@ -693,15 +711,15 @@ impl<'tt> TtParser<'tt> {
                 }
             }
 
-            assert!(!self.cur_items.is_empty());
+            assert!(!self.cur_mps.is_empty());
         }
     }
 
     fn ambiguity_error(&self, token_span: rustc_span::Span) -> NamedParseResult {
         let nts = self
-            .bb_items
+            .bb_mps
             .iter()
-            .map(|item| match item.top_elts[item.idx] {
+            .map(|mp| match mp.tts[mp.idx] {
                 TokenTree::MetaVarDecl(_, bind, Some(kind)) => {
                     format!("{} ('{}')", kind, bind)
                 }
@@ -715,7 +733,7 @@ impl<'tt> TtParser<'tt> {
             format!(
                 "local ambiguity when calling macro `{}`: multiple parsing options: {}",
                 self.macro_name,
-                match self.next_items.len() {
+                match self.next_mps.len() {
                     0 => format!("built-in NTs {}.", nts),
                     1 => format!("built-in NTs {} or 1 other option.", nts),
                     n => format!("built-in NTs {} or {} other options.", nts, n),
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index b3ed6b8e4db..d91871c7e57 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -211,7 +211,7 @@ fn parse_tree(
                     let (separator, kleene) =
                         parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
                     // Count the number of captured "names" (i.e., named metavars)
-                    let name_captures = macro_parser::count_names(&sequence);
+                    let name_captures = macro_parser::count_metavar_decls(&sequence);
                     TokenTree::Sequence(
                         delim_span,
                         Lrc::new(SequenceRepetition {
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index ace0c9df58d..e37251c9c24 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -215,6 +215,10 @@ declare_features! (
     /// Allows patterns with concurrent by-move and by-ref bindings.
     /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
     (accepted, move_ref_pattern, "1.49.0", Some(68354), None),
+    /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
+    (accepted, native_link_modifiers, "1.61.0", Some(81490), None),
+    /// Allows specifying the whole-archive link modifier
+    (accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None),
     /// Allows using `#![no_std]`.
     (accepted, no_std, "1.6.0", None, None),
     /// Allows defining identifiers beyond ASCII.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index feef7295254..28466315c86 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -400,6 +400,8 @@ declare_features! (
     (active, generic_arg_infer, "1.55.0", Some(85077), None),
     /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
     (active, generic_associated_types, "1.23.0", Some(44265), None),
+    /// An extension to the `generic_associated_types` feature, allowing incomplete features.
+    (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
     /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
     (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
     /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
@@ -446,16 +448,12 @@ declare_features! (
     (active, must_not_suspend, "1.57.0", Some(83310), None),
     /// Allows using `#[naked]` on functions.
     (active, naked_functions, "1.9.0", Some(32408), None),
-    /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
-    (active, native_link_modifiers, "1.53.0", Some(81490), None),
     /// Allows specifying the as-needed link modifier
     (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
     /// Allows specifying the bundle link modifier
     (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
     /// Allows specifying the verbatim link modifier
     (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
-    /// Allows specifying the whole-archive link modifier
-    (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
     /// Allow negative trait implementations.
     (active, negative_impls, "1.44.0", Some(68318), None),
     /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index a2f97f65708..352f369f0d4 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -78,7 +78,7 @@ pub enum DefKind {
     Const,
     /// Constant generic parameter: `struct Foo<const N: usize> { ... }`
     ConstParam,
-    Static,
+    Static(ast::Mutability),
     /// Refers to the struct or enum variant's constructor.
     ///
     /// The reason `Ctor` exists in addition to [`DefKind::Struct`] and
@@ -128,7 +128,7 @@ impl DefKind {
                 "crate"
             }
             DefKind::Mod => "module",
-            DefKind::Static => "static",
+            DefKind::Static(..) => "static",
             DefKind::Enum => "enum",
             DefKind::Variant => "variant",
             DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant",
@@ -202,7 +202,7 @@ impl DefKind {
             DefKind::Fn
             | DefKind::Const
             | DefKind::ConstParam
-            | DefKind::Static
+            | DefKind::Static(..)
             | DefKind::Ctor(..)
             | DefKind::AssocFn
             | DefKind::AssocConst => Some(Namespace::ValueNS),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 19fc77fb74b..10871df3ab9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1530,7 +1530,7 @@ impl Expr<'_> {
     pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
         match self.kind {
             ExprKind::Path(QPath::Resolved(_, ref path)) => {
-                matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static, _) | Res::Err)
+                matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static(_), _) | Res::Err)
             }
 
             // Type ascription inherits its place expression kind from its
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 5b8300ab530..a41e0374f41 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -161,15 +161,15 @@ pub enum LiteralKind {
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
     /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"
-    RawStr { n_hashes: u16, err: Option<RawStrError> },
+    RawStr { n_hashes: u8, err: Option<RawStrError> },
     /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"
-    RawByteStr { n_hashes: u16, err: Option<RawStrError> },
+    RawByteStr { n_hashes: u8, err: Option<RawStrError> },
 }
 
 /// Error produced validating a raw string. Represents cases like:
 /// - `r##~"abcde"##`: `InvalidStarter`
 /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
-/// - Too many `#`s (>65535): `TooManyDelimiters`
+/// - Too many `#`s (>255): `TooManyDelimiters`
 // perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum RawStrError {
@@ -178,7 +178,7 @@ pub enum RawStrError {
     /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
     /// may have intended to terminate it.
     NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
-    /// More than 65535 `#`s exist.
+    /// More than 255 `#`s exist.
     TooManyDelimiters { found: usize },
 }
 
@@ -698,12 +698,12 @@ impl Cursor<'_> {
     }
 
     /// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
-    fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u16, Option<RawStrError>) {
+    fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option<RawStrError>) {
         // Wrap the actual function to handle the error with too many hashes.
         // This way, it eats the whole raw string.
         let (n_hashes, err) = self.raw_string_unvalidated(prefix_len);
-        // Only up to 65535 `#`s are allowed in raw strings
-        match u16::try_from(n_hashes) {
+        // Only up to 255 `#`s are allowed in raw strings
+        match u8::try_from(n_hashes) {
             Ok(num) => (num, err),
             // We lie about the number of hashes here :P
             Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })),
diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs
index 548de67449a..07daee06f0f 100644
--- a/compiler/rustc_lexer/src/tests.rs
+++ b/compiler/rustc_lexer/src/tests.rs
@@ -2,7 +2,7 @@ use super::*;
 
 use expect_test::{expect, Expect};
 
-fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option<RawStrError>) {
+fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) {
     let s = &format!("r{}", s);
     let mut cursor = Cursor::new(s);
     cursor.bump();
@@ -68,13 +68,13 @@ fn test_unterminated_no_pound() {
 
 #[test]
 fn test_too_many_hashes() {
-    let max_count = u16::MAX;
+    let max_count = u8::MAX;
     let mut hashes: String = "#".repeat(max_count.into());
 
-    // Valid number of hashes (65535 = 2^16 - 1), but invalid string.
+    // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string.
     check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' }));
 
-    // One more hash sign (65536 = 2^16) becomes too many.
+    // One more hash sign (256 = 2^8) becomes too many.
     hashes.push('#');
     check_raw_str(
         &hashes,
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 8476c2bfcc4..0324ac3641e 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,5 +1,5 @@
 #![feature(nll)]
-#![feature(native_link_modifiers)]
+#![cfg_attr(bootstrap, feature(native_link_modifiers))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 
 // NOTE: This crate only exists to allow linking on mingw targets.
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index c3a76112391..1cbfb0bd554 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -125,13 +125,18 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
 
             // Do this outside the above loop so we don't depend on modifiers coming
             // after kinds
-            if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) {
+            let mut modifiers_count = 0;
+            for item in items.iter().filter(|item| item.has_name(sym::modifiers)) {
                 if let Some(modifiers) = item.value_str() {
+                    modifiers_count += 1;
                     let span = item.name_value_literal_span().unwrap();
+                    let mut has_duplicate_modifiers = false;
                     for modifier in modifiers.as_str().split(',') {
                         let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
                             Some(m) => (m, modifier.starts_with('+')),
                             None => {
+                                // Note: this error also excludes the case with empty modifier
+                                // string, like `modifiers = ""`.
                                 sess.span_err(
                                     span,
                                     "invalid linking modifier syntax, expected '+' or '-' prefix \
@@ -143,6 +148,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
 
                         match (modifier, &mut lib.kind) {
                             ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                                if bundle.is_some() {
+                                    has_duplicate_modifiers = true;
+                                }
                                 *bundle = Some(value);
                             }
                             ("bundle", _) => {
@@ -153,9 +161,17 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
                                 );
                             }
 
-                            ("verbatim", _) => lib.verbatim = Some(value),
+                            ("verbatim", _) => {
+                                if lib.verbatim.is_some() {
+                                    has_duplicate_modifiers = true;
+                                }
+                                lib.verbatim = Some(value);
+                            }
 
                             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                                if whole_archive.is_some() {
+                                    has_duplicate_modifiers = true;
+                                }
                                 *whole_archive = Some(value);
                             }
                             ("whole-archive", _) => {
@@ -168,6 +184,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
 
                             ("as-needed", NativeLibKind::Dylib { as_needed })
                             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                                if as_needed.is_some() {
+                                    has_duplicate_modifiers = true;
+                                }
                                 *as_needed = Some(value);
                             }
                             ("as-needed", _) => {
@@ -190,12 +209,22 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
                             }
                         }
                     }
+                    if has_duplicate_modifiers {
+                        let msg =
+                            "same modifier is used multiple times in a single `modifiers` argument";
+                        sess.span_err(item.span(), msg);
+                    }
                 } else {
                     let msg = "must be of the form `#[link(modifiers = \"...\")]`";
                     sess.span_err(item.span(), msg);
                 }
             }
 
+            if modifiers_count > 1 {
+                let msg = "multiple `modifiers` arguments in a single `#[link]` attribute";
+                sess.span_err(m.span, msg);
+            }
+
             // In general we require #[link(name = "...")] but we allow
             // #[link(wasm_import_module = "...")] without the `name`.
             let requires_name = kind_specified || lib.wasm_import_module.is_none();
@@ -349,6 +378,15 @@ impl Collector<'_> {
                 .drain_filter(|lib| {
                     if let Some(lib_name) = lib.name {
                         if lib_name.as_str() == passed_lib.name {
+                            // FIXME: This whole logic is questionable, whether modifiers are
+                            // involved or not, library reordering and kind overriding without
+                            // explicit `:rename` in particular.
+                            if lib.has_modifiers() || passed_lib.has_modifiers() {
+                                self.tcx.sess.span_err(
+                                    self.tcx.def_span(lib.foreign_module.unwrap()),
+                                    "overriding linking modifiers from command line is not supported"
+                                );
+                            }
                             if passed_lib.kind != NativeLibKind::Unspecified {
                                 lib.kind = passed_lib.kind;
                             }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e88ef68c722..8c765249007 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1464,21 +1464,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
     fn is_foreign_item(self, id: DefIndex) -> bool {
         match self.kind(id) {
-            EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => {
-                true
-            }
+            EntryKind::ForeignStatic | EntryKind::ForeignFn(_) => true,
             _ => false,
         }
     }
 
-    fn static_mutability(self, id: DefIndex) -> Option<hir::Mutability> {
-        match self.kind(id) {
-            EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not),
-            EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut),
-            _ => None,
-        }
-    }
-
     #[inline]
     fn def_key(self, index: DefIndex) -> DefKey {
         *self
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 70358ae0e22..5a2c59b4601 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -165,7 +165,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
     is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
-    static_mutability => { cdata.static_mutability(def_id.index) }
     item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
     trait_of_item => { cdata.get_trait_of_item(def_id.index) }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index a219b9eb2be..4541cf2c059 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -797,7 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::AssocTy
         | DefKind::Fn
         | DefKind::Const
-        | DefKind::Static
+        | DefKind::Static(..)
         | DefKind::Ctor(..)
         | DefKind::AssocFn
         | DefKind::AssocConst
@@ -831,7 +831,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         | DefKind::AssocConst
         | DefKind::TyParam
         | DefKind::ConstParam
-        | DefKind::Static
+        | DefKind::Static(..)
         | DefKind::Const
         | DefKind::Fn
         | DefKind::ForeignMod
@@ -875,7 +875,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
         DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::AssocConst
-        | DefKind::Static
+        | DefKind::Static(..)
         | DefKind::Const => (true, false),
         // Full-fledged functions
         DefKind::AssocFn | DefKind::Fn => {
@@ -920,7 +920,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::AssocConst
         | DefKind::TyParam
         | DefKind::ConstParam
-        | DefKind::Static
+        | DefKind::Static(..)
         | DefKind::Const
         | DefKind::ForeignMod
         | DefKind::TyAlias
@@ -954,7 +954,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::AssocTy
         | DefKind::Fn
         | DefKind::Const
-        | DefKind::Static
+        | DefKind::Static(..)
         | DefKind::Ctor(..)
         | DefKind::AssocFn
         | DefKind::AssocConst
@@ -1390,8 +1390,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.encode_ident_span(def_id, item.ident);
 
         let entry_kind = match item.kind {
-            hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic,
-            hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic,
+            hir::ItemKind::Static(..) => EntryKind::Static,
             hir::ItemKind::Const(_, body_id) => {
                 let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
                 let const_data = self.encode_rendered_const_for_body(body_id);
@@ -1906,11 +1905,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 };
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignFn(self.lazy(data)));
             }
-            hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignMutStatic);
-            }
-            hir::ForeignItemKind::Static(_, hir::Mutability::Not) => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignImmStatic);
+            hir::ForeignItemKind::Static(..) => {
+                record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic);
             }
             hir::ForeignItemKind::Type => {
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 204284ffaa3..06581033129 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -338,10 +338,8 @@ define_tables! {
 enum EntryKind {
     AnonConst,
     Const,
-    ImmStatic,
-    MutStatic,
-    ForeignImmStatic,
-    ForeignMutStatic,
+    Static,
+    ForeignStatic,
     ForeignMod,
     ForeignType,
     GlobalAsm,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 8afa6e70e41..f9d24b68634 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -228,7 +228,7 @@ impl<'hir> Map<'hir> {
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
         let def_kind = match self.find(hir_id)? {
             Node::Item(item) => match item.kind {
-                ItemKind::Static(..) => DefKind::Static,
+                ItemKind::Static(_, mt, _) => DefKind::Static(mt),
                 ItemKind::Const(..) => DefKind::Const,
                 ItemKind::Fn(..) => DefKind::Fn,
                 ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
@@ -248,7 +248,7 @@ impl<'hir> Map<'hir> {
             },
             Node::ForeignItem(item) => match item.kind {
                 ForeignItemKind::Fn(..) => DefKind::Fn,
-                ForeignItemKind::Static(..) => DefKind::Static,
+                ForeignItemKind::Static(_, mt) => DefKind::Static(mt),
                 ForeignItemKind::Type => DefKind::ForeignTy,
             },
             Node::TraitItem(item) => match item.kind {
@@ -471,19 +471,15 @@ impl<'hir> Map<'hir> {
     /// Returns the `BodyOwnerKind` of this `LocalDefId`.
     ///
     /// Panics if `LocalDefId` does not have an associated body.
-    pub fn body_owner_kind(self, id: HirId) -> BodyOwnerKind {
-        match self.get(id) {
-            Node::Item(&Item { kind: ItemKind::Const(..), .. })
-            | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. })
-            | Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. })
-            | Node::AnonConst(_) => BodyOwnerKind::Const,
-            Node::Ctor(..)
-            | Node::Item(&Item { kind: ItemKind::Fn(..), .. })
-            | Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. })
-            | Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(..), .. }) => BodyOwnerKind::Fn,
-            Node::Item(&Item { kind: ItemKind::Static(_, m, _), .. }) => BodyOwnerKind::Static(m),
-            Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => BodyOwnerKind::Closure,
-            node => bug!("{:#?} is not a body node", node),
+    pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
+        match self.tcx.def_kind(def_id) {
+            DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
+                BodyOwnerKind::Const
+            }
+            DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
+            DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
+            DefKind::Static(mt) => BodyOwnerKind::Static(mt),
+            dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
         }
     }
 
@@ -494,16 +490,17 @@ impl<'hir> Map<'hir> {
     /// This should only be used for determining the context of a body, a return
     /// value of `Some` does not always suggest that the owner of the body is `const`,
     /// just that it has to be checked as if it were.
-    pub fn body_const_context(self, did: LocalDefId) -> Option<ConstContext> {
-        let hir_id = self.local_def_id_to_hir_id(did);
-        let ccx = match self.body_owner_kind(hir_id) {
+    pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
+        let ccx = match self.body_owner_kind(def_id) {
             BodyOwnerKind::Const => ConstContext::Const,
             BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
 
-            BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None,
-            BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn,
+            BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
+            BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
+                ConstContext::ConstFn
+            }
             BodyOwnerKind::Fn
-                if self.tcx.has_attr(did.to_def_id(), sym::default_method_body_is_const) =>
+                if self.tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const) =>
             {
                 ConstContext::ConstFn
             }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 50d9c8e98b9..b2dd67fb16d 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -950,9 +950,8 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
     match (kind, body.source.promoted) {
         (_, Some(i)) => write!(w, "{:?} in ", i)?,
         (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
-        (DefKind::Static, _) => {
-            write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
-        }
+        (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
+        (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
         (_, _) if is_function => write!(w, "fn ")?,
         (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
         _ => bug!("Unexpected def kind {:?}", kind),
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 6d7e7ef0cb0..bf45269e06f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -586,12 +586,6 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
-    query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
-        desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
-        separate_provide_extern
-    }
-
     /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
     query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
         desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 388109e6512..075928c889d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1379,3 +1379,50 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         ControlFlow::CONTINUE
     }
 }
+
+/// Finds the max universe present
+pub struct MaxUniverse {
+    max_universe: ty::UniverseIndex,
+}
+
+impl MaxUniverse {
+    pub fn new() -> Self {
+        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
+    }
+
+    pub fn max_universe(self) -> ty::UniverseIndex {
+        self.max_universe
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::Placeholder(placeholder) = t.kind() {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::ConstKind::Placeholder(placeholder) = c.val() {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        c.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::RePlaceholder(placeholder) = *r {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        ControlFlow::CONTINUE
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dfc405b1195..7b12ec50b0d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2147,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> {
         match instance {
             ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
                 DefKind::Const
-                | DefKind::Static
+                | DefKind::Static(..)
                 | DefKind::AssocConst
                 | DefKind::Ctor(..)
                 | DefKind::AnonConst
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fecc5d805fc..21650fbb75d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -912,12 +912,25 @@ pub trait PrettyPrinter<'tcx>:
                 }
 
                 for (assoc_item_def_id, term) in assoc_items {
-                    // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
-                    if let Some(ty) = term.skip_binder().ty() &&
-                       let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = ty.kind() &&
-                       Some(*item_def_id) == self.tcx().lang_items().generator_return() {
-                        continue;
-                    }
+                    // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
+                    // unless we can find out what generator return type it comes from.
+                    let term = if let Some(ty) = term.skip_binder().ty()
+                        && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
+                        && Some(*item_def_id) == self.tcx().lang_items().generator_return()
+                    {
+                        if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
+                            let return_ty = substs.as_generator().return_ty();
+                            if !return_ty.is_ty_infer() {
+                                return_ty.into()
+                            } else {
+                                continue;
+                            }
+                        } else {
+                            continue;
+                        }
+                    } else {
+                        term.skip_binder()
+                    };
 
                     if first {
                         p!("<");
@@ -928,7 +941,7 @@ pub trait PrettyPrinter<'tcx>:
 
                     p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name));
 
-                    match term.skip_binder() {
+                    match term {
                         Term::Ty(ty) => {
                             p!(print(ty))
                         }
@@ -1188,7 +1201,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
                 match self.tcx().def_kind(def.did) {
-                    DefKind::Static | DefKind::Const | DefKind::AssocConst => {
+                    DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => {
                         p!(print_value_path(def.did, substs))
                     }
                     _ => {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 1b07dc6eb37..7d9a917d04c 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -533,8 +533,14 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns `true` if the node pointed to by `def_id` is a `static` item.
+    #[inline]
     pub fn is_static(self, def_id: DefId) -> bool {
-        self.static_mutability(def_id).is_some()
+        matches!(self.def_kind(def_id), DefKind::Static(_))
+    }
+
+    #[inline]
+    pub fn static_mutability(self, def_id: DefId) -> Option<hir::Mutability> {
+        if let DefKind::Static(mt) = self.def_kind(def_id) { Some(mt) } else { None }
     }
 
     /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute.
@@ -543,6 +549,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item.
+    #[inline]
     pub fn is_mutable_static(self, def_id: DefId) -> bool {
         self.static_mutability(def_id) == Some(hir::Mutability::Mut)
     }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index ab3dc8f020c..901635dc488 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -41,7 +41,7 @@ crate fn mir_built<'tcx>(
 /// Construct the MIR for a given `DefId`.
 fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
     let id = tcx.hir().local_def_id_to_hir_id(def.did);
-    let body_owner_kind = tcx.hir().body_owner_kind(id);
+    let body_owner_kind = tcx.hir().body_owner_kind(def.did);
     let typeck_results = tcx.typeck_opt_const_arg(def);
 
     // Ensure unsafeck and abstract const building is ran before we steal the THIR.
@@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         check_overflow |= tcx.sess.overflow_checks();
         // Constants always need overflow checks.
         check_overflow |= matches!(
-            tcx.hir().body_owner_kind(hir_id),
+            tcx.hir().body_owner_kind(def.did),
             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
         );
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index cab5fcd179b..e6afc89baa0 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -523,7 +523,7 @@ impl<'tcx> Cx<'tcx> {
                                         }
                                     }
 
-                                    Res::Def(DefKind::Static, def_id) => {
+                                    Res::Def(DefKind::Static(_), def_id) => {
                                         InlineAsmOperand::SymStatic { def_id }
                                     }
 
@@ -901,7 +901,7 @@ impl<'tcx> Cx<'tcx> {
 
             // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
             // a constant reference (or constant raw pointer for `static mut`) in MIR
-            Res::Def(DefKind::Static, id) => {
+            Res::Def(DefKind::Static(_), id) => {
                 let ty = self.tcx.static_ptr_ty(id);
                 let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
                 let kind = if self.tcx.is_thread_local_static(id) {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index d21fbb9edff..57aec867856 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -420,7 +420,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => {
                 let pattern_error = match res {
                     Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span),
-                    Res::Def(DefKind::Static, _) => PatternError::StaticInPattern(span),
+                    Res::Def(DefKind::Static(_), _) => PatternError::StaticInPattern(span),
                     _ => PatternError::NonConstPath(span),
                 };
                 self.errors.push(pattern_error);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 23e5f0b4f30..b6bb56990ed 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -59,11 +59,10 @@ impl<'tcx> MirPass<'tcx> for Inline {
 }
 
 fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
-    let def_id = body.source.def_id();
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let def_id = body.source.def_id().expect_local();
 
     // Only do inlining into fn bodies.
-    if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() {
+    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() {
         return false;
     }
     if body.source.promoted.is_some() {
@@ -77,9 +76,10 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     }
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
         tcx,
-        def_id,
+        def_id.to_def_id(),
         param_env,
         ObligationCause::misc(body.span, hir_id),
     );
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 48b6951f10e..c6a99aae588 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -158,7 +158,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::Fn
         | DefKind::Const
         | DefKind::ConstParam
-        | DefKind::Static
+        | DefKind::Static(_)
         | DefKind::Ctor(_, _)
         | DefKind::AssocFn
         | DefKind::AssocConst
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 92c5d329f6e..5ab412dc777 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -597,15 +597,13 @@ impl<'a> StringReader<'a> {
         }
     }
 
-    /// Note: It was decided to not add a test case, because it would be too big.
-    /// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180>
     fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
         self.fatal_span_(
             start,
             self.pos,
             &format!(
                 "too many `#` symbols: raw strings may be delimited \
-                by up to 65535 `#` symbols, but found {}",
+                by up to 255 `#` symbols, but found {}",
                 found
             ),
         )
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index fdf93e58932..7b21ab32f4f 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -734,7 +734,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
 
     fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
         let body_id = body.id();
-        let owner_id = self.tcx.hir().body_owner(body_id);
+        let owner_id = self.tcx.hir().body_owner_def_id(body_id);
 
         debug!(
             "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 1f286d557ca..85168aad1c3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -553,7 +553,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         }
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
-            DefKind::Const | DefKind::Static | DefKind::TraitAlias | DefKind::TyAlias => {
+            DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
                 if vis.is_accessible_from(module.to_def_id(), self.tcx) {
                     self.update(def_id, level);
                 }
@@ -1243,12 +1243,12 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         let def = def.filter(|(kind, _)| {
             matches!(
                 kind,
-                DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static
+                DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static(_)
             )
         });
         if let Some((kind, def_id)) = def {
             let is_local_static =
-                if let DefKind::Static = kind { def_id.is_local() } else { false };
+                if let DefKind::Static(_) = kind { def_id.is_local() } else { false };
             if !self.item_is_accessible(def_id) && !is_local_static {
                 let sess = self.tcx.sess;
                 let sm = sess.source_map();
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 34218e87b51..b706547f7fc 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -701,8 +701,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             }
 
             // These items live in the value namespace.
-            ItemKind::Static(..) => {
-                let res = Res::Def(DefKind::Static, def_id);
+            ItemKind::Static(_, mt, _) => {
+                let res = Res::Def(DefKind::Static(mt), def_id);
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
@@ -907,7 +907,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         let def_id = local_def_id.to_def_id();
         let (def_kind, ns) = match item.kind {
             ForeignItemKind::Fn(..) => (DefKind::Fn, ValueNS),
-            ForeignItemKind::Static(..) => (DefKind::Static, ValueNS),
+            ForeignItemKind::Static(_, mt, _) => (DefKind::Static(mt), ValueNS),
             ForeignItemKind::TyAlias(..) => (DefKind::ForeignTy, TypeNS),
             ForeignItemKind::MacCall(_) => unreachable!(),
         };
@@ -963,7 +963,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             Res::Def(
                 DefKind::Fn
                 | DefKind::AssocFn
-                | DefKind::Static
+                | DefKind::Static(_)
                 | DefKind::Const
                 | DefKind::AssocConst
                 | DefKind::Ctor(..),
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index bb05a3d7510..400adf20cba 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -300,7 +300,7 @@ impl<'a> PathSource<'a> {
                 Res::Def(
                     DefKind::Ctor(_, CtorKind::Const | CtorKind::Fn)
                         | DefKind::Const
-                        | DefKind::Static
+                        | DefKind::Static(_)
                         | DefKind::Fn
                         | DefKind::AssocFn
                         | DefKind::AssocConst
@@ -1830,7 +1830,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 }
                 Some(res)
             }
-            Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => {
+            Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static(_), _) => {
                 // This is unambiguously a fresh binding, either syntactically
                 // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
                 // to something unusable as a pattern (e.g., constructor function),
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index d071d66ffa6..08a990c65ff 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -701,7 +701,7 @@ impl<'tcx> SaveContext<'tcx> {
                 let parent_def_id = self.tcx.parent(def_id).unwrap();
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) })
             }
-            Res::Def(HirDefKind::Static | HirDefKind::Const | HirDefKind::AssocConst, _) => {
+            Res::Def(HirDefKind::Static(_) | HirDefKind::Const | HirDefKind::AssocConst, _) => {
                 Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) })
             }
             Res::Def(HirDefKind::AssocFn, decl_id) => {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 44a2e2bdc85..856436e44db 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1948,9 +1948,6 @@ fn parse_native_lib_kind(
     kind: &str,
     error_format: ErrorOutputType,
 ) -> (NativeLibKind, Option<bool>) {
-    let is_nightly = nightly_options::match_is_nightly_build(matches);
-    let enable_unstable = nightly_options::is_unstable_enabled(matches);
-
     let (kind, modifiers) = match kind.split_once(':') {
         None => (kind, None),
         Some((kind, modifiers)) => (kind, Some(modifiers)),
@@ -1972,7 +1969,7 @@ fn parse_native_lib_kind(
                     "linking modifier can't be used with library kind `static-nobundle`",
                 )
             }
-            if !is_nightly {
+            if !nightly_options::match_is_nightly_build(matches) {
                 early_error(
                     error_format,
                     "library kind `static-nobundle` are currently unstable and only accepted on \
@@ -1988,23 +1985,7 @@ fn parse_native_lib_kind(
     };
     match modifiers {
         None => (kind, None),
-        Some(modifiers) => {
-            if !is_nightly {
-                early_error(
-                    error_format,
-                    "linking modifiers are currently unstable and only accepted on \
-                the nightly compiler",
-                );
-            }
-            if !enable_unstable {
-                early_error(
-                    error_format,
-                    "linking modifiers are currently unstable, \
-                the `-Z unstable-options` flag must also be passed to use it",
-                )
-            }
-            parse_native_lib_modifiers(kind, modifiers, error_format)
-        }
+        Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
     }
 }
 
@@ -2012,7 +1993,23 @@ fn parse_native_lib_modifiers(
     mut kind: NativeLibKind,
     modifiers: &str,
     error_format: ErrorOutputType,
+    matches: &getopts::Matches,
 ) -> (NativeLibKind, Option<bool>) {
+    let report_unstable_modifier = |modifier| {
+        if !nightly_options::is_unstable_enabled(matches) {
+            let why = if nightly_options::match_is_nightly_build(matches) {
+                " and only accepted on the nightly compiler"
+            } else {
+                ", the `-Z unstable-options` flag must also be passed to use it"
+            };
+            early_error(
+                error_format,
+                &format!("{modifier} linking modifier is currently unstable{why}"),
+            )
+        }
+    };
+
+    let mut has_duplicate_modifiers = false;
     let mut verbatim = None;
     for modifier in modifiers.split(',') {
         let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
@@ -2026,6 +2023,10 @@ fn parse_native_lib_modifiers(
 
         match (modifier, &mut kind) {
             ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                report_unstable_modifier(modifier);
+                if bundle.is_some() {
+                    has_duplicate_modifiers = true;
+                }
                 *bundle = Some(value);
             }
             ("bundle", _) => early_error(
@@ -2034,9 +2035,18 @@ fn parse_native_lib_modifiers(
                     `static` linking kind",
             ),
 
-            ("verbatim", _) => verbatim = Some(value),
+            ("verbatim", _) => {
+                report_unstable_modifier(modifier);
+                if verbatim.is_some() {
+                    has_duplicate_modifiers = true;
+                }
+                verbatim = Some(value);
+            }
 
             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                if whole_archive.is_some() {
+                    has_duplicate_modifiers = true;
+                }
                 *whole_archive = Some(value);
             }
             ("whole-archive", _) => early_error(
@@ -2047,6 +2057,10 @@ fn parse_native_lib_modifiers(
 
             ("as-needed", NativeLibKind::Dylib { as_needed })
             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                report_unstable_modifier(modifier);
+                if as_needed.is_some() {
+                    has_duplicate_modifiers = true;
+                }
                 *as_needed = Some(value);
             }
             ("as-needed", _) => early_error(
@@ -2055,6 +2069,8 @@ fn parse_native_lib_modifiers(
                     `dylib` and `framework` linking kinds",
             ),
 
+            // Note: this error also excludes the case with empty modifier
+            // string, like `modifiers = ""`.
             _ => early_error(
                 error_format,
                 &format!(
@@ -2064,6 +2080,9 @@ fn parse_native_lib_modifiers(
             ),
         }
     }
+    if has_duplicate_modifiers {
+        report_unstable_modifier("duplicating")
+    }
 
     (kind, verbatim)
 }
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 281fc887633..c1fd3c7c61b 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -75,6 +75,12 @@ pub struct NativeLib {
     pub dll_imports: Vec<DllImport>,
 }
 
+impl NativeLib {
+    pub fn has_modifiers(&self) -> bool {
+        self.verbatim.is_some() || self.kind.has_modifiers()
+    }
+}
+
 #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct DllImport {
     pub name: Symbol,
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index a33f94013d2..6a8775bd10b 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -43,6 +43,20 @@ pub enum NativeLibKind {
     Unspecified,
 }
 
+impl NativeLibKind {
+    pub fn has_modifiers(&self) -> bool {
+        match self {
+            NativeLibKind::Static { bundle, whole_archive } => {
+                bundle.is_some() || whole_archive.is_some()
+            }
+            NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
+                as_needed.is_some()
+            }
+            NativeLibKind::RawDylib | NativeLibKind::Unspecified => false,
+        }
+    }
+}
+
 rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
 
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
@@ -53,6 +67,12 @@ pub struct NativeLib {
     pub verbatim: Option<bool>,
 }
 
+impl NativeLib {
+    pub fn has_modifiers(&self) -> bool {
+        self.verbatim.is_some() || self.kind.has_modifiers()
+    }
+}
+
 rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
 
 /// A path that has been canonicalized along with its original, non-canonicalized form
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 84dbad846dd..0bca0a99e15 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -272,6 +272,7 @@ symbols! {
         __D,
         __H,
         __S,
+        __awaitee,
         __try_var,
         _d,
         _e,
@@ -722,6 +723,7 @@ symbols! {
         generators,
         generic_arg_infer,
         generic_associated_types,
+        generic_associated_types_extended,
         generic_const_exprs,
         generic_param_attrs,
         get_context,
@@ -1018,7 +1020,6 @@ symbols! {
         pattern_parentheses,
         phantom_data,
         pin,
-        pinned,
         platform_intrinsics,
         plugin,
         plugin_registrar,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 36eddf7784b..d95512bb88f 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -5,6 +5,7 @@ use super::*;
 
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
+use crate::traits::project::ProjectAndUnifyResult;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{Region, RegionVid, Term};
 
@@ -751,7 +752,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                     debug!("Projecting and unifying projection predicate {:?}", predicate);
 
                     match project::poly_project_and_unify_type(select, &obligation.with(p)) {
-                        Err(e) => {
+                        ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
                             debug!(
                                 "evaluate_nested_obligations: Unable to unify predicate \
                                  '{:?}' '{:?}', bailing out",
@@ -759,11 +760,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             );
                             return false;
                         }
-                        Ok(Err(project::InProgress)) => {
+                        ProjectAndUnifyResult::Recursive => {
                             debug!("evaluate_nested_obligations: recursive projection predicate");
                             return false;
                         }
-                        Ok(Ok(Some(v))) => {
+                        ProjectAndUnifyResult::Holds(v) => {
                             // We only care about sub-obligations
                             // when we started out trying to unify
                             // some inference variables. See the comment above
@@ -782,7 +783,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                                 }
                             }
                         }
-                        Ok(Ok(None)) => {
+                        ProjectAndUnifyResult::FailedNormalization => {
                             // It's ok not to make progress when have no inference variables -
                             // in that case, we were only performing unification to check if an
                             // error occurred (which would indicate that it's impossible for our
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 4b6784aee97..866bb6109e0 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -19,6 +19,7 @@ use rustc_middle::ty::{self, TyCtxt};
 /// obligations *could be* resolved if we wanted to.
 ///
 /// This also expects that `trait_ref` is fully normalized.
+#[instrument(level = "debug", skip(tcx))]
 pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
@@ -27,11 +28,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
     let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
     debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
-    debug!(
-        "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
-        (param_env, trait_ref),
-        trait_ref.def_id()
-    );
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
@@ -80,25 +76,22 @@ pub fn codegen_fulfill_obligation<'tcx>(
             }
         };
 
-        debug!("fulfill_obligation: selection={:?}", selection);
+        debug!(?selection);
 
         // Currently, we use a fulfillment context to completely resolve
         // all nested obligations. This is because they can inform the
         // inference of the impl's type parameters.
         let mut fulfill_cx = FulfillmentContext::new();
         let impl_source = selection.map(|predicate| {
-            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
         });
         let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
 
-        // There should be no opaque types during codegen, they all get revealed.
-        let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-        if !opaque_types.is_empty() {
-            bug!("{:#?}", opaque_types);
-        }
+        // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
+        // as they will get constrained elsewhere, too.
+        let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-        debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
+        debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
         Ok(&*tcx.arena.alloc(impl_source))
     })
 }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 1b862834467..d0b8b0281c5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
 use std::marker::PhantomData;
 
 use super::const_evaluatable;
-use super::project;
+use super::project::{self, ProjectAndUnifyResult};
 use super::select::SelectionContext;
 use super::wf;
 use super::CodeAmbiguity;
@@ -753,8 +753,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         }
 
         match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
-            Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
-            Ok(Ok(None)) => {
+            ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
+            ProjectAndUnifyResult::FailedNormalization => {
                 stalled_on.clear();
                 stalled_on.extend(substs_infer_vars(
                     self.selcx,
@@ -763,10 +763,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 ProcessResult::Unchanged
             }
             // Let the caller handle the recursion
-            Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![
+            ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![
                 project_obligation.with(project_obligation.predicate.to_predicate(tcx)),
             ])),
-            Err(e) => ProcessResult::Error(CodeProjectionError(e)),
+            ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
+                ProcessResult::Error(CodeProjectionError(e))
+            }
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d4ec677a0b1..2251f992e4d 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::traits::select::OverflowError;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
@@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
     }
 }
 
+/// Takes the place of a
+/// Result<
+///     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
+///     MismatchedProjectionTypes<'tcx>,
+/// >
+pub(super) enum ProjectAndUnifyResult<'tcx> {
+    Holds(Vec<PredicateObligation<'tcx>>),
+    FailedNormalization,
+    Recursive,
+    MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
+}
+
 /// Evaluates constraints of the form:
 ///
 ///     for<...> <T as Trait>::U == V
@@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
 pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &PolyProjectionObligation<'tcx>,
-) -> Result<
-    Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
-    MismatchedProjectionTypes<'tcx>,
-> {
+) -> ProjectAndUnifyResult<'tcx> {
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|_snapshot| {
+    let r = infcx.commit_if_ok(|_snapshot| {
+        let old_universe = infcx.universe();
         let placeholder_predicate =
             infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let new_universe = infcx.universe();
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
-        let result = project_and_unify_type(selcx, &placeholder_obligation)?;
-        Ok(result)
-    })
+        match project_and_unify_type(selcx, &placeholder_obligation) {
+            ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
+            ProjectAndUnifyResult::Holds(obligations)
+                if old_universe != new_universe
+                    && selcx.tcx().features().generic_associated_types_extended =>
+            {
+                // If the `generic_associated_types_extended` feature is active, then we ignore any
+                // obligations references lifetimes from any universe greater than or equal to the
+                // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`,
+                // which isn't quite what we want. Ideally, we want either an implied
+                // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we
+                // substitute concrete regions. There is design work to be done here; until then,
+                // however, this allows experimenting potential GAT features without running into
+                // well-formedness issues.
+                let new_obligations = obligations
+                    .into_iter()
+                    .filter(|obligation| {
+                        let mut visitor = MaxUniverse::new();
+                        obligation.predicate.visit_with(&mut visitor);
+                        visitor.max_universe() < new_universe
+                    })
+                    .collect();
+                Ok(ProjectAndUnifyResult::Holds(new_obligations))
+            }
+            other => Ok(other),
+        }
+    });
+
+    match r {
+        Ok(inner) => inner,
+        Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err),
+    }
 }
 
 /// Evaluates constraints of the form:
@@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
 /// If successful, this may result in additional obligations.
 ///
 /// See [poly_project_and_unify_type] for an explanation of the return value.
+#[tracing::instrument(level = "debug", skip(selcx))]
 fn project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionObligation<'tcx>,
-) -> Result<
-    Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
-    MismatchedProjectionTypes<'tcx>,
-> {
-    debug!(?obligation, "project_and_unify_type");
-
+) -> ProjectAndUnifyResult<'tcx> {
     let mut obligations = vec![];
 
     let infcx = selcx.infcx();
@@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>(
         &mut obligations,
     ) {
         Ok(Some(n)) => n,
-        Ok(None) => return Ok(Ok(None)),
-        Err(InProgress) => return Ok(Err(InProgress)),
+        Ok(None) => return ProjectAndUnifyResult::FailedNormalization,
+        Err(InProgress) => return ProjectAndUnifyResult::Recursive,
     };
     debug!(?normalized, ?obligations, "project_and_unify_type result");
     let actual = obligation.predicate.term;
@@ -231,11 +267,11 @@ fn project_and_unify_type<'cx, 'tcx>(
     match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
-            Ok(Ok(Some(obligations)))
+            ProjectAndUnifyResult::Holds(obligations)
         }
         Err(err) => {
-            debug!("project_and_unify_type: equating types encountered error {:?}", err);
-            Err(MismatchedProjectionTypes { err })
+            debug!("equating types encountered error {:?}", err);
+            ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err })
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 42f17721f9b..4f033d45c1f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -21,6 +21,7 @@ use super::{
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::project::ProjectAndUnifyResult;
 use crate::traits::project::ProjectionCacheKeyExt;
 use crate::traits::ProjectionCacheKey;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -525,7 +526,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let data = bound_predicate.rebind(data);
                     let project_obligation = obligation.with(data);
                     match project::poly_project_and_unify_type(self, &project_obligation) {
-                        Ok(Ok(Some(mut subobligations))) => {
+                        ProjectAndUnifyResult::Holds(mut subobligations) => {
                             'compute_res: {
                                 // If we've previously marked this projection as 'complete', then
                                 // use the final cached result (either `EvaluatedToOk` or
@@ -573,9 +574,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 res
                             }
                         }
-                        Ok(Ok(None)) => Ok(EvaluatedToAmbig),
-                        Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
-                        Err(_) => Ok(EvaluatedToErr),
+                        ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
+                        ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur),
+                        ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
                     }
                 }
 
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index b04d304d2ca..0d522702e67 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2186,7 +2186,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
 
             // Case 3. Reference to a top-level value.
-            DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => {
+            DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static(_) => {
                 path_segs.push(PathSeg(def_id, last));
             }
 
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 7f5ab8e4f42..d2b462b5959 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         hir::Path {
                             res:
                                 hir::def::Res::Def(
-                                    hir::def::DefKind::Static | hir::def::DefKind::Const,
+                                    hir::def::DefKind::Static(_) | hir::def::DefKind::Const,
                                     def_id,
                                 ),
                             ..
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index ecbd1e46349..2065de24754 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -52,7 +52,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             wbcx.visit_node_id(param.pat.span, param.hir_id);
         }
         // Type only exists for constants and statics, not functions.
-        match self.tcx.hir().body_owner_kind(item_id) {
+        match self.tcx.hir().body_owner_kind(item_def_id) {
             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
                 wbcx.visit_node_id(body.value.span, item_id);
             }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 6a4c5d4a6c7..3078eba9dc2 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -85,7 +85,6 @@ pub fn provide(providers: &mut Providers) {
         impl_trait_ref,
         impl_polarity,
         is_foreign_item,
-        static_mutability,
         generator_kind,
         codegen_fn_attrs,
         asm_target_features,
@@ -2602,20 +2601,6 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-fn static_mutability(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::Mutability> {
-    match tcx.hir().get_if_local(def_id) {
-        Some(
-            Node::Item(&hir::Item { kind: hir::ItemKind::Static(_, mutbl, _), .. })
-            | Node::ForeignItem(&hir::ForeignItem {
-                kind: hir::ForeignItemKind::Static(_, mutbl),
-                ..
-            }),
-        ) => Some(mutbl),
-        Some(_) => None,
-        _ => bug!("static_mutability applied to non-local def-id {:?}", def_id),
-    }
-}
-
 fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
     match tcx.hir().get_if_local(def_id) {
         Some(Node::Expr(&rustc_hir::Expr {
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index b08e08a27d0..055e391d706 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -723,10 +723,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         let upvars = tcx.upvars_mentioned(self.body_owner);
 
         // For purposes of this function, generator and closures are equivalent.
-        let body_owner_is_closure = matches!(
-            tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)),
-            hir::BodyOwnerKind::Closure,
-        );
+        let body_owner_is_closure =
+            matches!(tcx.hir().body_owner_kind(self.body_owner), hir::BodyOwnerKind::Closure,);
 
         // If we have a nested closure, we want to include the fake reads present in the nested closure.
         if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 1464420090b..85e9a670ffb 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -404,7 +404,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             )
             | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
 
-            Res::Def(DefKind::Static, _) => {
+            Res::Def(DefKind::Static(_), _) => {
                 Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
             }