about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs8
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs29
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs8
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs106
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs428
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs38
-rw-r--r--library/proc_macro/src/lib.rs4
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow.rs30
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow_uwp.rs9
-rw-r--r--library/std/src/sys/pal/windows/thread.rs5
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/mir-opt/building/match/match_false_edges.main.built.after.mir2
-rw-r--r--tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir8
-rw-r--r--tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir6
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff8
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff8
-rw-r--r--tests/run-make/hir-tree/Makefile8
-rw-r--r--tests/run-make/hir-tree/input.rs3
-rw-r--r--tests/ui/extern/issue-95829.stderr9
-rw-r--r--tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr13
-rw-r--r--tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs11
-rw-r--r--tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr27
-rw-r--r--tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs79
-rw-r--r--tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr106
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.rs97
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.stderr158
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.rs21
-rw-r--r--tests/ui/nll/match-cfg-fake-edges2.stderr4
-rw-r--r--tests/ui/parser/fn-header-semantic-fail.rs5
-rw-r--r--tests/ui/parser/fn-header-semantic-fail.stderr68
-rw-r--r--tests/ui/parser/no-const-fn-in-extern-block.rs1
-rw-r--r--tests/ui/parser/no-const-fn-in-extern-block.stderr27
-rw-r--r--tests/ui/parser/unsafe-foreign-mod-2.stderr9
-rw-r--r--tests/ui/proc-macro/auxiliary/api/mod.rs2
-rw-r--r--tests/ui/unpretty/hir-tree.rs10
42 files changed, 893 insertions, 512 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c10a6258d39..e29ef591bcb 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2484,6 +2484,14 @@ pub enum CoroutineKind {
 }
 
 impl CoroutineKind {
+    pub fn span(self) -> Span {
+        match self {
+            CoroutineKind::Async { span, .. } => span,
+            CoroutineKind::Gen { span, .. } => span,
+            CoroutineKind::AsyncGen { span, .. } => span,
+        }
+    }
+
     pub fn is_async(self) -> bool {
         matches!(self, CoroutineKind::Async { .. })
     }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 28a13d275a5..ac3799e7a05 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -68,7 +68,7 @@ ast_passes_extern_block_suggestion = if you meant to declare an externally defin
 
 ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
     .label = in this `extern` block
-    .suggestion = remove the qualifiers
+    .suggestion = remove this qualifier
 
 ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
     .label = in this `extern` block
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 80c62d3fecf..093a985495c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -514,13 +514,32 @@ impl<'a> AstValidator<'a> {
     }
 
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
-    fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
-        if header.has_qualifiers() {
+    fn check_foreign_fn_headerless(
+        &self,
+        // Deconstruct to ensure exhaustiveness
+        FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
+    ) {
+        let report_err = |span| {
             self.dcx().emit_err(errors::FnQualifierInExtern {
-                span: ident.span,
+                span: span,
                 block: self.current_extern_span(),
-                sugg_span: span.until(ident.span.shrink_to_lo()),
             });
+        };
+        match unsafety {
+            Unsafe::Yes(span) => report_err(span),
+            Unsafe::No => (),
+        }
+        match coroutine_kind {
+            Some(knd) => report_err(knd.span()),
+            None => (),
+        }
+        match constness {
+            Const::Yes(span) => report_err(span),
+            Const::No => (),
+        }
+        match ext {
+            Extern::None => (),
+            Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span),
         }
     }
 
@@ -1145,7 +1164,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
                 self.check_defaultness(fi.span, *defaultness);
                 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
-                self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
+                self.check_foreign_fn_headerless(sig.header);
                 self.check_foreign_item_ascii_only(fi.ident);
             }
             ForeignItemKind::TyAlias(box TyAlias {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 9e8c1d7f5fd..8ae9f7d3966 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -270,11 +270,10 @@ pub struct FnBodyInExtern {
 #[diag(ast_passes_extern_fn_qualifiers)]
 pub struct FnQualifierInExtern {
     #[primary_span]
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
     pub span: Span,
     #[label]
     pub block: Span,
-    #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
-    pub sugg_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 68c1770c1d4..140566e8da9 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -24,8 +24,6 @@ pub(crate) mod ffi;
 pub(crate) mod map_data;
 pub mod mapgen;
 
-const VAR_ALIGN: Align = Align::EIGHT;
-
 /// A context object for maintaining all state needed by the coverageinfo module.
 pub struct CrateCoverageContext<'ll, 'tcx> {
     /// Coverage data for each instrumented function identified by DefId.
@@ -226,7 +224,8 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
     llvm::set_global_constant(llglobal, true);
     llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
     llvm::set_section(llglobal, &covmap_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
     cx.add_used_global(llglobal);
 }
 
@@ -256,7 +255,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
     llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
     llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
     llvm::set_section(llglobal, covfun_section_name);
-    llvm::set_alignment(llglobal, VAR_ALIGN);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
     llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
     cx.add_used_global(llglobal);
 }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 0c91dc6d3c6..582a1806688 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -33,10 +33,6 @@ rustc_index::newtype_index! {
     pub struct CounterId {}
 }
 
-impl CounterId {
-    pub const START: Self = Self::ZERO;
-}
-
 rustc_index::newtype_index! {
     /// ID of a coverage-counter expression. Values ascend from 0.
     ///
@@ -55,10 +51,6 @@ rustc_index::newtype_index! {
     pub struct ExpressionId {}
 }
 
-impl ExpressionId {
-    pub const START: Self = Self::ZERO;
-}
-
 /// Enum that can hold a constant zero value, the ID of an physical coverage
 /// counter, or the ID of a coverage-counter expression.
 ///
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 1ea671a4f79..367c391b45a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -214,12 +214,77 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// ## False edges
     ///
-    /// We don't want to have the exact structure of the decision tree be
-    /// visible through borrow checking. False edges ensure that the CFG as
-    /// seen by borrow checking doesn't encode this. False edges are added:
+    /// We don't want to have the exact structure of the decision tree be visible through borrow
+    /// checking. Specifically we want borrowck to think that:
+    /// - at any point, any or none of the patterns and guards seen so far may have been tested;
+    /// - after the match, any of the patterns may have matched.
     ///
-    /// * From each pre-binding block to the next pre-binding block.
-    /// * From each otherwise block to the next pre-binding block.
+    /// For example, all of these would fail to error if borrowck could see the real CFG (examples
+    /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`):
+    /// ```ignore (too many errors, this is already in the test suite)
+    /// let x = String::new();
+    /// let _ = match true {
+    ///     _ => {},
+    ///     _ => drop(x),
+    /// };
+    /// // Borrowck must not know the second arm is never run.
+    /// drop(x); //~ ERROR use of moved value
+    ///
+    /// let x;
+    /// # let y = true;
+    /// match y {
+    ///     _ if { x = 2; true } => {},
+    ///     // Borrowck must not know the guard is always run.
+    ///     _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    /// };
+    ///
+    /// let x = String::new();
+    /// # let y = true;
+    /// match y {
+    ///     false if { drop(x); true } => {},
+    ///     // Borrowck must not know the guard is not run in the `true` case.
+    ///     true => drop(x), //~ ERROR use of moved value: `x`
+    ///     false => {},
+    /// };
+    ///
+    /// # let mut y = (true, true);
+    /// let r = &mut y.1;
+    /// match y {
+    ///     //~^ ERROR cannot use `y.1` because it was mutably borrowed
+    ///     (false, true) => {}
+    ///     // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+    ///     (true, _) => drop(r),
+    ///     (false, _) => {}
+    /// };
+    /// ```
+    ///
+    /// We add false edges to act as if we were naively matching each arm in order. What we need is
+    /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
+    /// block to next candidate D's pre-binding block. For maximum precision (needed for deref
+    /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
+    /// avoid loops).
+    ///
+    /// This turns out to be easy to compute: that block is the `start_block` of the first call to
+    /// `match_candidates` where D is the first candidate in the list.
+    ///
+    /// For example:
+    /// ```rust
+    /// # let (x, y) = (true, true);
+    /// match (x, y) {
+    ///   (true, true) => 1,
+    ///   (false, true) => 2,
+    ///   (true, false) => 3,
+    ///   _ => 4,
+    /// }
+    /// # ;
+    /// ```
+    /// In this example, the pre-binding block of arm 1 has a false edge to the block for result
+    /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
+    /// of the next arm.
+    ///
+    /// On top of this, we also add a false edge from the otherwise_block of each guard to the
+    /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
+    /// guards may have run.
     #[instrument(level = "debug", skip(self, arms))]
     pub(crate) fn match_expr(
         &mut self,
@@ -365,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         for candidate in candidates {
             candidate.visit_leaves(|leaf_candidate| {
                 if let Some(ref mut prev) = previous_candidate {
-                    prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
+                    assert!(leaf_candidate.false_edge_start_block.is_some());
+                    prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
                 }
                 previous_candidate = Some(leaf_candidate);
             });
@@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
 
     /// The block before the `bindings` have been established.
     pre_binding_block: Option<BasicBlock>,
-    /// The pre-binding block of the next candidate.
-    next_candidate_pre_binding_block: Option<BasicBlock>,
+
+    /// The earliest block that has only candidates >= this one as descendents. Used for false
+    /// edges, see the doc for [`Builder::match_expr`].
+    false_edge_start_block: Option<BasicBlock>,
+    /// The `false_edge_start_block` of the next candidate.
+    next_candidate_start_block: Option<BasicBlock>,
 }
 
 impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@@ -1033,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
             or_span: None,
             otherwise_block: None,
             pre_binding_block: None,
-            next_candidate_pre_binding_block: None,
+            false_edge_start_block: None,
+            next_candidate_start_block: None,
         }
     }
 
@@ -1325,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         otherwise_block: BasicBlock,
         candidates: &mut [&mut Candidate<'_, 'tcx>],
     ) {
+        if let [first, ..] = candidates {
+            if first.false_edge_start_block.is_none() {
+                first.false_edge_start_block = Some(start_block);
+            }
+        }
+
         match candidates {
             [] => {
                 // If there are no candidates that still need testing, we're done. Since all matches are
@@ -1545,6 +1622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             .into_iter()
             .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
             .collect();
+        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
     }
 
     /// Try to merge all of the subcandidates of the given candidate into one. This avoids
@@ -1564,6 +1642,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let any_matches = self.cfg.start_new_block();
             let or_span = candidate.or_span.take().unwrap();
             let source_info = self.source_info(or_span);
+            if candidate.false_edge_start_block.is_none() {
+                candidate.false_edge_start_block =
+                    candidate.subcandidates[0].false_edge_start_block;
+            }
             for subcandidate in mem::take(&mut candidate.subcandidates) {
                 let or_block = subcandidate.pre_binding_block.unwrap();
                 self.cfg.goto(or_block, source_info, any_matches);
@@ -1979,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut block = candidate.pre_binding_block.unwrap();
 
-        if candidate.next_candidate_pre_binding_block.is_some() {
+        if candidate.next_candidate_start_block.is_some() {
             let fresh_block = self.cfg.start_new_block();
             self.false_edges(
                 block,
                 fresh_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 candidate_source_info,
             );
             block = fresh_block;
@@ -2132,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.false_edges(
                 otherwise_post_guard_block,
                 otherwise_block,
-                candidate.next_candidate_pre_binding_block,
+                candidate.next_candidate_start_block,
                 source_info,
             );
 
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index b5dd9dcc7b4..65715253647 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -59,7 +59,7 @@ fn coverage_ids_info<'tcx>(
             _ => None,
         })
         .max()
-        .unwrap_or(CounterId::START);
+        .unwrap_or(CounterId::ZERO);
 
     CoverageIdsInfo { max_counter_id }
 }
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index d40421fa064..c632712f5a9 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -11,13 +11,14 @@ use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{
     self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
     TermKind, Ty, TyCtxt, UintTy,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
@@ -182,14 +183,15 @@ fn encode_fnsig<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_sig.output().fold_with(&mut type_folder);
     s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
 
     // Encode the parameter types
     let tys = fn_sig.inputs();
     if !tys.is_empty() {
         for ty in tys {
-            let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options);
+            let ty = ty.fold_with(&mut type_folder);
             s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
         }
 
@@ -523,15 +525,9 @@ fn encode_ty<'tcx>(
 
         ty::Array(ty0, len) => {
             // A<array-length><element-type>
+            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
             let mut s = String::from("A");
-            let _ = write!(
-                s,
-                "{}",
-                &len.try_to_scalar()
-                    .unwrap()
-                    .to_target_usize(&tcx.data_layout)
-                    .expect("Array lens are defined in usize")
-            );
+            let _ = write!(s, "{}", &len);
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -756,278 +752,208 @@ fn encode_ty<'tcx>(
     typeid
 }
 
-/// Transforms predicates for being encoded and used in the substitution dictionary.
-fn transform_predicates<'tcx>(
+struct TransformTy<'tcx> {
     tcx: TyCtxt<'tcx>,
-    predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
-) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
-    tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| {
-        match predicate.skip_binder() {
-            ty::ExistentialPredicate::Trait(trait_ref) => {
-                let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
-                Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
-                    ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
-                )))
-            }
-            ty::ExistentialPredicate::Projection(..) => None,
-            ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
-        }
-    }))
-}
-
-/// Transforms args for being encoded and used in the substitution dictionary.
-fn transform_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
     options: TransformTyOptions,
-) -> GenericArgsRef<'tcx> {
-    let args = args.iter().map(|arg| match arg.unpack() {
-        GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
-        GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(),
-        _ => arg,
-    });
-    tcx.mk_args_from_iter(args)
+    parents: Vec<Ty<'tcx>>,
 }
 
-// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
-// c_void types into unit types unconditionally, generalizes pointers if
-// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
-// TransformTyOptions::NORMALIZE_INTEGERS option is set.
-fn transform_ty<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut ty: Ty<'tcx>,
-    parents: &mut Vec<Ty<'tcx>>,
-    options: TransformTyOptions,
-) -> Ty<'tcx> {
-    match ty.kind() {
-        ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {}
+impl<'tcx> TransformTy<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
+        TransformTy { tcx, options, parents: Vec::new() }
+    }
+}
 
-        ty::Bool => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: on all platforms that Rust's currently supports, its size and alignment are
-                // 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
-                //
-                // Clang represents bool as an 8-bit unsigned integer.
-                ty = tcx.types.u8;
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
+    // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
+    // all c_void types into unit types unconditionally, generalizes pointers if
+    // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
+    // TransformTyOptions::NORMALIZE_INTEGERS option is set.
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match t.kind() {
+            ty::Array(..)
+            | ty::Closure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineClosure(..)
+            | ty::CoroutineWitness(..)
+            | ty::Float(..)
+            | ty::FnDef(..)
+            | ty::Foreign(..)
+            | ty::Never
+            | ty::Slice(..)
+            | ty::Str
+            | ty::Tuple(..) => t.super_fold_with(self),
+
+            ty::Bool => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: on all platforms that Rust's currently supports, its size and alignment
+                    // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+                    //
+                    // Clang represents bool as an 8-bit unsigned integer.
+                    self.tcx.types.u8
+                } else {
+                    t
+                }
             }
-        }
 
-        ty::Char => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Since #118032, char is guaranteed to have the same size, alignment, and function
-                // call ABI as u32 on all platforms.
-                ty = tcx.types.u32;
+            ty::Char => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Since #118032, char is guaranteed to have the same size, alignment, and
+                    // function call ABI as u32 on all platforms.
+                    self.tcx.types.u32
+                } else {
+                    t
+                }
             }
-        }
 
-        ty::Int(..) | ty::Uint(..) => {
-            if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
-                // All platforms we currently support have a C platform, and as a consequence,
-                // isize/usize are at least 16-bit wide for all of them.
-                //
-                // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
-                match ty.kind() {
-                    ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.i16,
-                        32 => ty = tcx.types.i32,
-                        64 => ty = tcx.types.i64,
-                        128 => ty = tcx.types.i128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
-                        16 => ty = tcx.types.u16,
-                        32 => ty = tcx.types.u32,
-                        64 => ty = tcx.types.u64,
-                        128 => ty = tcx.types.u128,
-                        _ => bug!(
-                            "transform_ty: unexpected pointer width `{}`",
-                            tcx.sess.target.pointer_width
-                        ),
-                    },
-                    _ => (),
+            ty::Int(..) | ty::Uint(..) => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
+                    // wide. All platforms we currently support have a C platform, and as a
+                    // consequence, isize/usize are at least 16-bit wide for all of them.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+                    match t.kind() {
+                        ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.i16,
+                            32 => self.tcx.types.i32,
+                            64 => self.tcx.types.i64,
+                            128 => self.tcx.types.i128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.u16,
+                            32 => self.tcx.types.u32,
+                            64 => self.tcx.types.u64,
+                            128 => self.tcx.types.u128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        _ => t,
+                    }
+                } else {
+                    t
                 }
             }
-        }
-
-        _ if ty.is_unit() => {}
-
-        ty::Tuple(tys) => {
-            ty = Ty::new_tup_from_iter(
-                tcx,
-                tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)),
-            );
-        }
-
-        ty::Array(ty0, len) => {
-            let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
 
-            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len);
-        }
+            ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
 
-        ty::Slice(ty0) => {
-            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options));
-        }
-
-        ty::Adt(adt_def, args) => {
-            if ty.is_c_void(tcx) {
-                ty = Ty::new_unit(tcx);
-            } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
-            {
-                ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
-            } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty)
-            {
-                // Don't transform repr(transparent) types with an user-defined CFI encoding to
-                // preserve the user-defined CFI encoding.
-                if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
-                    return ty;
-                }
-                let variant = adt_def.non_enum_variant();
-                let param_env = tcx.param_env(variant.def_id);
-                let field = variant.fields.iter().find(|field| {
-                    let ty = tcx.type_of(field.did).instantiate_identity();
-                    let is_zst =
-                        tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
-                    !is_zst
-                });
-                if let Some(field) = field {
-                    let ty0 = tcx.type_of(field.did).instantiate(tcx, args);
-                    // Generalize any repr(transparent) user-defined type that is either a pointer
-                    // or reference, and either references itself or any other type that contains or
-                    // references itself, to avoid a reference cycle.
-
-                    // If the self reference is not through a pointer, for example, due
-                    // to using `PhantomData`, need to skip normalizing it if we hit it again.
-                    parents.push(ty);
-                    if ty0.is_any_ptr() && ty0.contains(ty) {
-                        ty = transform_ty(
-                            tcx,
-                            ty0,
-                            parents,
-                            options | TransformTyOptions::GENERALIZE_POINTERS,
-                        );
+            ty::Adt(adt_def, args) => {
+                if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
+                {
+                    // Don't transform repr(transparent) types with an user-defined CFI encoding to
+                    // preserve the user-defined CFI encoding.
+                    if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+                        return t;
+                    }
+                    let variant = adt_def.non_enum_variant();
+                    let param_env = self.tcx.param_env(variant.def_id);
+                    let field = variant.fields.iter().find(|field| {
+                        let ty = self.tcx.type_of(field.did).instantiate_identity();
+                        let is_zst = self
+                            .tcx
+                            .layout_of(param_env.and(ty))
+                            .is_ok_and(|layout| layout.is_zst());
+                        !is_zst
+                    });
+                    if let Some(field) = field {
+                        let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
+                        // Generalize any repr(transparent) user-defined type that is either a
+                        // pointer or reference, and either references itself or any other type that
+                        // contains or references itself, to avoid a reference cycle.
+
+                        // If the self reference is not through a pointer, for example, due
+                        // to using `PhantomData`, need to skip normalizing it if we hit it again.
+                        self.parents.push(t);
+                        let ty = if ty0.is_any_ptr() && ty0.contains(t) {
+                            let options = self.options;
+                            self.options |= TransformTyOptions::GENERALIZE_POINTERS;
+                            let ty = ty0.fold_with(self);
+                            self.options = options;
+                            ty
+                        } else {
+                            ty0.fold_with(self)
+                        };
+                        self.parents.pop();
+                        ty
                     } else {
-                        ty = transform_ty(tcx, ty0, parents, options);
+                        // Transform repr(transparent) types without non-ZST field into ()
+                        self.tcx.types.unit
                     }
-                    parents.pop();
                 } else {
-                    // Transform repr(transparent) types without non-ZST field into ()
-                    ty = Ty::new_unit(tcx);
+                    t.super_fold_with(self)
                 }
-            } else {
-                ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options));
             }
-        }
-
-        ty::FnDef(def_id, args) => {
-            ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::Closure(def_id, args) => {
-            ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::CoroutineClosure(def_id, args) => {
-            ty = Ty::new_coroutine_closure(
-                tcx,
-                *def_id,
-                transform_args(tcx, args, parents, options),
-            );
-        }
 
-        ty::Coroutine(def_id, args) => {
-            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options));
-        }
-
-        ty::Ref(region, ty0, ..) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                } else {
-                    ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
-                }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
+            ty::Ref(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    }
                 } else {
-                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
+                    t.super_fold_with(self)
                 }
             }
-        }
 
-        ty::RawPtr(ptr_ty, _) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
+            ty::RawPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                    }
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
+                    t.super_fold_with(self)
                 }
-            } else {
-                if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
+            }
+
+            ty::FnPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
+                    t.super_fold_with(self)
                 }
             }
-        }
 
-        ty::FnPtr(fn_sig) => {
-            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
-            } else {
-                let parameters: Vec<Ty<'tcx>> = fn_sig
-                    .skip_binder()
-                    .inputs()
-                    .iter()
-                    .map(|ty| transform_ty(tcx, *ty, parents, options))
-                    .collect();
-                let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options);
-                ty = Ty::new_fn_ptr(
-                    tcx,
-                    ty::Binder::bind_with_vars(
-                        tcx.mk_fn_sig(
-                            parameters,
-                            output,
-                            fn_sig.c_variadic(),
-                            fn_sig.unsafety(),
-                            fn_sig.abi(),
-                        ),
-                        fn_sig.bound_vars(),
-                    ),
+            ty::Dynamic(predicates, _region, kind) => {
+                let predicates = self.tcx.mk_poly_existential_predicates_from_iter(
+                    predicates.iter().filter_map(|predicate| match predicate.skip_binder() {
+                        ty::ExistentialPredicate::Trait(trait_ref) => {
+                            let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id);
+                            Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+                                ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref),
+                            )))
+                        }
+                        ty::ExistentialPredicate::Projection(..) => None,
+                        ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
+                    }),
                 );
-            }
-        }
 
-        ty::Dynamic(predicates, _region, kind) => {
-            ty = Ty::new_dynamic(
-                tcx,
-                transform_predicates(tcx, predicates),
-                tcx.lifetimes.re_erased,
-                *kind,
-            );
-        }
+                Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind)
+            }
 
-        ty::Alias(..) => {
-            ty = transform_ty(
-                tcx,
-                tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty),
-                parents,
-                options,
-            );
-        }
+            ty::Alias(..) => {
+                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
+            }
 
-        ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
-            bug!("transform_ty: unexpected `{:?}`", ty.kind());
+            ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
+                bug!("fold_ty: unexpected `{:?}`", t.kind());
+            }
         }
     }
 
-    ty
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 }
 
 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
@@ -1068,7 +994,8 @@ pub fn typeid_for_fnabi<'tcx>(
     // Encode the return type
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options);
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
     typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
 
     // Encode the parameter types
@@ -1080,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>(
         let mut pushed_arg = false;
         for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
             pushed_arg = true;
-            let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = arg.layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
         if !pushed_arg {
@@ -1093,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>(
             if fn_abi.args[n].mode == PassMode::Ignore {
                 continue;
             }
-            let ty =
-                transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
+            let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
 
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index dd1f2322c41..4ecb0ea7cd9 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -8,7 +8,9 @@ use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
+};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
@@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>(
                 ));
             }
 
+            let err_if_unsized = |field: &FieldDef, err_msg: &str| {
+                let field_ty = tcx.type_of(field.did);
+                let is_unsized = tcx
+                    .try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
+                    .map(|f| !f.is_sized(tcx, cx.param_env))
+                    .map_err(|e| {
+                        error(
+                            cx,
+                            LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
+                        )
+                    })?;
+
+                if is_unsized {
+                    cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
+                    Err(error(cx, LayoutError::Unknown(ty)))
+                } else {
+                    Ok(())
+                }
+            };
+
+            if def.is_struct() {
+                if let Some((_, fields_except_last)) =
+                    def.non_enum_variant().fields.raw.split_last()
+                {
+                    for f in fields_except_last {
+                        err_if_unsized(f, "only the last field of a struct can be unsized")?;
+                    }
+                }
+            } else {
+                for f in def.all_fields() {
+                    err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
+                }
+            }
+
             let get_discriminant_type =
                 |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
 
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index e04bf69ef51..01c449563ee 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1360,7 +1360,7 @@ impl Literal {
     }
 
     /// Byte character literal.
-    #[unstable(feature = "proc_macro_byte_character", issue = "115268")]
+    #[stable(feature = "proc_macro_byte_character", since = "CURRENT_RUSTC_VERSION")]
     pub fn byte_character(byte: u8) -> Literal {
         let string = [byte].escape_ascii().to_string();
         Literal::new(bridge::LitKind::Byte, &string, None)
@@ -1374,7 +1374,7 @@ impl Literal {
     }
 
     /// C string literal.
-    #[unstable(feature = "proc_macro_c_str_literals", issue = "119750")]
+    #[stable(feature = "proc_macro_c_str_literals", since = "CURRENT_RUSTC_VERSION")]
     pub fn c_string(string: &CStr) -> Literal {
         let string = string.to_bytes().escape_ascii().to_string();
         Literal::new(bridge::LitKind::CStr, &string, None)
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index 627763da856..f93f31026f8 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -3,21 +3,12 @@
 use crate::sys::c;
 use crate::thread;
 
-use super::api;
-
-pub struct Handler;
-
-impl Handler {
-    pub unsafe fn new() -> Handler {
-        // This API isn't available on XP, so don't panic in that case and just
-        // pray it works out ok.
-        if c::SetThreadStackGuarantee(&mut 0x5000) == 0
-            && api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
-        {
-            panic!("failed to reserve stack space for exception handling");
-        }
-        Handler
-    }
+/// Reserve stack space for use in stack overflow exceptions.
+pub unsafe fn reserve_stack() {
+    let result = c::SetThreadStackGuarantee(&mut 0x5000);
+    // Reserving stack space is not critical so we allow it to fail in the released build of libstd.
+    // We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
+    debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
 }
 
 unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG {
@@ -36,9 +27,10 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
 }
 
 pub unsafe fn init() {
-    if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() {
-        panic!("failed to install exception handler");
-    }
+    let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
+    // Similar to the above, adding the stack overflow handler is allowed to fail
+    // but a debug assert is used so CI will still test that it normally works.
+    debug_assert!(!result.is_null(), "failed to install exception handler");
     // Set the thread stack guarantee for the main thread.
-    let _h = Handler::new();
+    reserve_stack();
 }
diff --git a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
index afdf7f566ae..9e9b3efaf1b 100644
--- a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs
@@ -1,11 +1,4 @@
 #![cfg_attr(test, allow(dead_code))]
 
-pub struct Handler;
-
-impl Handler {
-    pub fn new() -> Handler {
-        Handler
-    }
-}
-
+pub unsafe fn reserve_stack() {}
 pub unsafe fn init() {}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 80eee4e078d..fe174e1e340 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -48,9 +48,8 @@ impl Thread {
 
         extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
             unsafe {
-                // Next, set up our stack overflow handler which may get triggered if we run
-                // out of stack.
-                let _handler = stack_overflow::Handler::new();
+                // Next, reserve some stack space for if we otherwise run out of stack.
+                stack_overflow::reserve_stack();
                 // Finally, let's run some code.
                 Box::from_raw(main as *mut Box<dyn FnOnce()>)();
             }
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 40950e6ba44..347ea1223eb 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -86,7 +86,6 @@ run-make/foreign-exceptions/Makefile
 run-make/foreign-rust-exceptions/Makefile
 run-make/fpic/Makefile
 run-make/glibc-staticlib-args/Makefile
-run-make/hir-tree/Makefile
 run-make/inaccessible-temp-dir/Makefile
 run-make/include_bytes_deps/Makefile
 run-make/incr-add-rust-src-component/Makefile
diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
index b71b2412cdf..dfa31cfff6b 100644
--- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
@@ -48,7 +48,7 @@ fn main() -> () {
     }
 
     bb2: {
-        falseEdge -> [real: bb15, imaginary: bb6];
+        falseEdge -> [real: bb15, imaginary: bb3];
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
index e95a97b5b87..c3497c6989d 100644
--- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
@@ -40,7 +40,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
     }
 
     bb4: {
-        falseEdge -> [real: bb12, imaginary: bb9];
+        falseEdge -> [real: bb12, imaginary: bb7];
     }
 
     bb5: {
@@ -48,7 +48,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
     }
 
     bb6: {
-        falseEdge -> [real: bb16, imaginary: bb3];
+        falseEdge -> [real: bb16, imaginary: bb1];
     }
 
     bb7: {
@@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
     }
 
     bb9: {
-        falseEdge -> [real: bb15, imaginary: bb6];
+        falseEdge -> [real: bb15, imaginary: bb5];
     }
 
     bb10: {
@@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
 
     bb14: {
         StorageDead(_10);
-        falseEdge -> [real: bb5, imaginary: bb9];
+        falseEdge -> [real: bb5, imaginary: bb7];
     }
 
     bb15: {
diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
index 80d3c2e5c23..4a1e4fb9ec5 100644
--- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir
@@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
     }
 
     bb2: {
-        falseEdge -> [real: bb9, imaginary: bb4];
+        falseEdge -> [real: bb9, imaginary: bb3];
     }
 
     bb3: {
@@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
     }
 
     bb4: {
-        falseEdge -> [real: bb12, imaginary: bb6];
+        falseEdge -> [real: bb12, imaginary: bb5];
     }
 
     bb5: {
@@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
 
     bb11: {
         StorageDead(_8);
-        falseEdge -> [real: bb1, imaginary: bb4];
+        falseEdge -> [real: bb1, imaginary: bb3];
     }
 
     bb12: {
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f7105dd2..ba333ba1a58 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 307f7105dd2..ba333ba1a58 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -60,11 +60,11 @@
       }
   
 -     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb3];
+-         falseEdge -> [real: bb13, imaginary: bb2];
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb5];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 -     }
 - 
 -     bb7: {
@@ -127,7 +127,7 @@
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb1, imaginary: bb5];
+-         falseEdge -> [real: bb1, imaginary: bb1];
 +         goto -> bb1;
       }
   
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb3];
+-         falseEdge -> [real: bb2, imaginary: bb2];
 +         goto -> bb2;
       }
   
diff --git a/tests/run-make/hir-tree/Makefile b/tests/run-make/hir-tree/Makefile
deleted file mode 100644
index b0450ea4bc5..00000000000
--- a/tests/run-make/hir-tree/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-# Test that hir-tree output doesn't crash and includes
-# the string constant we would expect to see.
-
-all:
-	$(RUSTC) -o $(TMPDIR)/input.hir -Z unpretty=hir-tree input.rs
-	$(CGREP) '"Hello, Rustaceans!\n"' < $(TMPDIR)/input.hir
diff --git a/tests/run-make/hir-tree/input.rs b/tests/run-make/hir-tree/input.rs
deleted file mode 100644
index 9d1a4e9e47d..00000000000
--- a/tests/run-make/hir-tree/input.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, Rustaceans!");
-}
diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr
index b902f0ef8f5..16504d1f0c9 100644
--- a/tests/ui/extern/issue-95829.stderr
+++ b/tests/ui/extern/issue-95829.stderr
@@ -16,17 +16,12 @@ LL | |     }
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/issue-95829.rs:4:14
+  --> $DIR/issue-95829.rs:4:5
    |
 LL | extern {
    | ------ in this `extern` block
 LL |     async fn L() {
-   |              ^
-   |
-help: remove the qualifiers
-   |
-LL |     fn L() {
-   |     ~~
+   |     ^^^^^ help: remove this qualifier
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs
deleted file mode 100644
index 03071c351a4..00000000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ force-host
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::Literal;
-
-fn test() {
-    Literal::byte_character(b'a'); //~ ERROR use of unstable library feature 'proc_macro_byte_character'
-}
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr
deleted file mode 100644
index c14d19381c8..00000000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'proc_macro_byte_character'
-  --> $DIR/feature-gate-proc_macro_byte_character.rs:9:5
-   |
-LL |     Literal::byte_character(b'a');
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #115268 <https://github.com/rust-lang/rust/issues/115268> for more information
-   = help: add `#![feature(proc_macro_byte_character)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs
deleted file mode 100644
index 1750fe952f5..00000000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ edition: 2021
-//@ force-host
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::Literal;
-
-fn test() {
-    Literal::c_string(c"a"); //~ ERROR use of unstable library feature 'proc_macro_c_str_literals'
-}
diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr
deleted file mode 100644
index 9bba1d50ce3..00000000000
--- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'proc_macro_c_str_literals'
-  --> $DIR/feature-gate-proc_macro_c_str_literals.rs:10:5
-   |
-LL |     Literal::c_string(c"a");
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #119750 <https://github.com/rust-lang/rust/issues/119750> for more information
-   = help: add `#![feature(proc_macro_c_str_literals)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
new file mode 100644
index 00000000000..0e07d21b2f5
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
@@ -0,0 +1,11 @@
+// Don't panic when iterating through the `hir::Map::parent_iter` of an RPITIT.
+
+pub trait Foo {
+    fn demo() -> impl Foo
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+    where
+        String: Copy;
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
new file mode 100644
index 00000000000..8ff8f12cdf4
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:7:9
+   |
+LL |         String: Copy;
+   |         ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/synthetic-hir-has-parent.rs:4:18
+   |
+LL |     fn demo() -> impl Foo
+   |                  ^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
new file mode 100644
index 00000000000..737a7ffbc29
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
@@ -0,0 +1,79 @@
+// Regression test for #121473
+// Checks that no ICE occurs when `size_of`
+// is applied to a struct that has an unsized
+// field which is not its last field
+
+use std::mem::size_of;
+
+pub struct BadStruct {
+    pub field1: i32,
+    pub field2: str, // Unsized field that is not the last field
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    pub field3: [u8; 16],
+}
+
+enum BadEnum1 {
+    Variant1 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+}
+
+enum BadEnum2 {
+    Variant1(
+        i32,
+        str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        [u8; 16]
+    ),
+}
+
+enum BadEnumMultiVariant {
+    Variant1(i32),
+    Variant2 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+    Variant3
+}
+
+union BadUnion {
+    field1: i32,
+    field2: str, // Unsized
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    field3: [u8; 16],
+}
+
+// Used to test that projection type fields that normalize
+// to a sized type do not cause problems
+struct StructWithProjections<'a>
+{
+    field1: <&'a [i32] as IntoIterator>::IntoIter,
+    field2: i32
+}
+
+pub fn main() {
+    let _a = &size_of::<BadStruct>();
+    assert_eq!(size_of::<BadStruct>(), 21);
+
+    let _a = &size_of::<BadEnum1>();
+    assert_eq!(size_of::<BadEnum1>(), 21);
+
+    let _a = &size_of::<BadEnum2>();
+    assert_eq!(size_of::<BadEnum2>(), 21);
+
+    let _a = &size_of::<BadEnumMultiVariant>();
+    assert_eq!(size_of::<BadEnumMultiVariant>(), 21);
+
+    let _a = &size_of::<BadUnion>();
+    assert_eq!(size_of::<BadUnion>(), 21);
+
+    let _a = &size_of::<StructWithProjections>();
+    assert_eq!(size_of::<StructWithProjections>(), 21);
+    let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 };
+}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
new file mode 100644
index 00000000000..626be7ac283
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
@@ -0,0 +1,106 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17
+   |
+LL |     pub field2: str, // Unsized field that is not the last field
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     pub field2: &str, // Unsized field that is not the last field
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     pub field2: Box<str>, // Unsized field that is not the last field
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9
+   |
+LL |         str, // Unsized
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         &str, // Unsized
+   |         +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         Box<str>, // Unsized
+   |         ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13
+   |
+LL |     field2: str, // Unsized
+   |             ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     field2: &str, // Unsized
+   |             +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     field2: Box<str>, // Unsized
+   |             ++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5
+   |
+LL |     field2: str, // Unsized
+   |     ^^^^^^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     field2: std::mem::ManuallyDrop<str>, // Unsized
+   |             +++++++++++++++++++++++   +
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/nll/match-cfg-fake-edges.rs b/tests/ui/nll/match-cfg-fake-edges.rs
index 1afc7931a6b..e349c2c8e2a 100644
--- a/tests/ui/nll/match-cfg-fake-edges.rs
+++ b/tests/ui/nll/match-cfg-fake-edges.rs
@@ -3,10 +3,46 @@
 
 #![feature(if_let_guard)]
 
+#[rustfmt::skip]
+fn all_patterns_are_tested() {
+    // Even though `x` is never actually moved out of, we don't want borrowck results to be based on
+    // whether MIR lowering reveals which patterns are unreachable.
+    let x = String::new();
+    match true {
+        _ => {},
+        _ => drop(x),
+    }
+    // Borrowck must not know the second arm is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = String::new();
+    if let _ = true { //~ WARN irrefutable
+    } else {
+        drop(x)
+    }
+    // Borrowck must not know the else branch is never run.
+    drop(x); //~ ERROR use of moved value
+
+    let x = (String::new(), String::new());
+    match x {
+        (y, _) | (_, y) => (),
+    }
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+
+    let x = (String::new(), String::new());
+    let ((y, _) | (_, y)) = x;
+    &x.0; //~ ERROR borrow of moved value
+    // Borrowck must not know the second pattern never matches.
+    &x.1; //~ ERROR borrow of moved value
+}
+
+#[rustfmt::skip]
 fn guard_always_precedes_arm(y: i32) {
-    let mut x;
     // x should always be initialized, as the only way to reach the arm is
     // through the guard.
+    let mut x;
     match y {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
@@ -14,56 +50,69 @@ fn guard_always_precedes_arm(y: i32) {
 
     let mut x;
     match y {
+        _ => 2,
+        0 | 2 if { x = 2; true } => x,
+    };
+
+    let mut x;
+    match y {
         0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
         _ => 2,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_skipped(y: i32) {
+    // Even though x *is* always initialized, we don't want to have borrowck results be based on
+    // whether MIR lowering reveals which patterns are exhaustive.
+    let x;
+    match y {
+        _ if { x = 2; true } => {},
+        // Borrowck must not know the guard is always run.
+        _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
+    };
+
     let x;
-    // Even though x *is* always initialized, we don't want to have borrowck
-    // results be based on whether patterns are exhaustive.
     match y {
         _ if { x = 2; true } => 1,
-        _ if {
-            x; //~ ERROR E0381
-            false
-        } => 2,
+        // Borrowck must not know the guard is always run.
+        _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 
     let x;
     match y {
         _ if let Some(()) = { x = 2; Some(()) } => 1,
-        _ if let Some(()) = {
-            x; //~ ERROR E0381
-            None
-        } => 2,
+        _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
         _ => 3,
     };
 }
 
+#[rustfmt::skip]
 fn guard_may_be_taken(y: bool) {
-    let x = String::new();
     // Even though x *is* never moved before the use, we don't want to have
     // borrowck results be based on whether patterns are disjoint.
+    let x = String::new();
+    match y {
+        false if { drop(x); true } => {},
+        // Borrowck must not know the guard is not run in the `true` case.
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
+    };
+
+    // Fine in the other order.
+    let x = String::new();
     match y {
-        false if { drop(x); true } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        true => drop(x),
+        false if { drop(x); true } => {},
+        false => {},
     };
 
     let x = String::new();
     match y {
-        false if let Some(()) = { drop(x); Some(()) } => 1,
-        true => {
-            x; //~ ERROR use of moved value: `x`
-            2
-        }
-        false => 3,
+        false if let Some(()) = { drop(x); Some(()) } => {},
+        true => drop(x), //~ ERROR use of moved value: `x`
+        false => {},
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
index a6261345cea..d692ded36fa 100644
--- a/tests/ui/nll/match-cfg-fake-edges.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -1,14 +1,128 @@
-error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:29:13
+warning: irrefutable `if let` pattern
+  --> $DIR/match-cfg-fake-edges.rs:19:8
+   |
+LL |     if let _ = true {
+   |        ^^^^^^^^^^^^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
+   = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:16:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         _ => drop(x),
+   |                   - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ => drop(x.clone()),
+   |                    ++++++++
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:24:10
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |         drop(x)
+   |              - value moved here
+...
+LL |     drop(x);
+   |          ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         drop(x.clone())
+   |               ++++++++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:30:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |          - value moved here
+LL |     }
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (ref y, _) | (_, y) => (),
+   |          +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:32:5
+   |
+LL |         (y, _) | (_, y) => (),
+   |                      - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (y, _) | (_, ref y) => (),
+   |                      +++
+
+error[E0382]: borrow of moved value: `x.0`
+  --> $DIR/match-cfg-fake-edges.rs:36:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |           - value moved here
+LL |     &x.0;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y)) = x;
+   |           +++
+
+error[E0382]: borrow of moved value: `x.1`
+  --> $DIR/match-cfg-fake-edges.rs:38:5
+   |
+LL |     let ((y, _) | (_, y)) = x;
+   |                       - value moved here
+...
+LL |     &x.1;
+   |     ^^^^ value borrowed here after move
+   |
+   = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y)) = x;
+   |                       +++
+
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/match-cfg-fake-edges.rs:72:19
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 ...
+LL |         _ => drop(x),
+   |         -         ^ `x` used here but it is possibly-uninitialized
+   |         |
+   |         if this pattern is matched, `x` is not initialized
+
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:79:16
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
 LL |         _ if { x = 2; true } => 1,
    |                ----- binding initialized here in some conditions
-LL |         _ if {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         // Borrowck must not know the guard is always run.
+LL |         _ if { x; false } => 2,
+   |                ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -16,16 +130,15 @@ LL |     let x = 0;
    |           +++
 
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:39:13
+  --> $DIR/match-cfg-fake-edges.rs:86:31
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
 LL |     match y {
 LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
    |                               ----- binding initialized here in some conditions
-LL |         _ if let Some(()) = {
-LL |             x;
-   |             ^ `x` used here but it isn't initialized
+LL |         _ if let Some(()) = { x; None } => 2,
+   |                               ^ `x` used here but it isn't initialized
    |
 help: consider assigning a value
    |
@@ -33,40 +146,39 @@ LL |     let x = 0;
    |           +++
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:53:13
+  --> $DIR/match-cfg-fake-edges.rs:99:22
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
-...
-LL |         false if { drop(x); true } => 1,
+LL |     match y {
+LL |         false if { drop(x); true } => {},
    |                         - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
+LL |         // Borrowck must not know the guard is not run in the `true` case.
+LL |         true => drop(x),
+   |                      ^ value used here after move
    |
 help: consider cloning the value if the performance cost is acceptable
    |
-LL |         false if { drop(x.clone()); true } => 1,
+LL |         false if { drop(x.clone()); true } => {},
    |                          ++++++++
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:63:13
+  --> $DIR/match-cfg-fake-edges.rs:114:22
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
 LL |     match y {
-LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+LL |         false if let Some(()) = { drop(x); Some(()) } => {},
    |                                        - value moved here
-LL |         true => {
-LL |             x;
-   |             ^ value used here after move
+LL |         true => drop(x),
+   |                      ^ value used here after move
    |
 help: consider cloning the value if the performance cost is acceptable
    |
-LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => {},
    |                                         ++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 11 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/nll/match-cfg-fake-edges2.rs b/tests/ui/nll/match-cfg-fake-edges2.rs
index 48f95e03b78..ac90fb9cd1e 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.rs
+++ b/tests/ui/nll/match-cfg-fake-edges2.rs
@@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
     let r = &mut y.1;
     // We don't actually test y.1 to select the second arm, but we don't want
     // borrowck results to be based on the order we match patterns.
-    match y { //~ ERROR cannot use `y.1` because it was mutably borrowed
-        (false, true) => 1,
-        (true, _) => {
-            r;
-            2
-        }
-        (false, _) => 3,
+    match y {
+        //~^ ERROR cannot use `y.1` because it was mutably borrowed
+        (false, true) => {}
+        // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
+        (true, _) => drop(r),
+        (false, _) => {}
+    };
+
+    // Fine in the other order.
+    let r = &mut y.1;
+    match y {
+        (true, _) => drop(r),
+        (false, true) => {}
+        (false, _) => {}
     };
 }
 
diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr
index 639cba1406a..0a228d62b92 100644
--- a/tests/ui/nll/match-cfg-fake-edges2.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges2.stderr
@@ -7,8 +7,8 @@ LL |     let r = &mut y.1;
 LL |     match y {
    |     ^^^^^^^ use of borrowed `y.1`
 ...
-LL |             r;
-   |             - borrow later used here
+LL |         (true, _) => drop(r),
+   |                           - borrow later used here
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs
index 25d7c3f35fc..6ed173b6854 100644
--- a/tests/ui/parser/fn-header-semantic-fail.rs
+++ b/tests/ui/parser/fn-header-semantic-fail.rs
@@ -48,6 +48,9 @@ fn main() {
         const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
         extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
         const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks
-        //~^ ERROR functions cannot be both `const` and `async`
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions in `extern` blocks
+        //~| ERROR functions cannot be both `const` and `async`
     }
 }
diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr
index 696d8e01b63..cfc54839eb7 100644
--- a/tests/ui/parser/fn-header-semantic-fail.stderr
+++ b/tests/ui/parser/fn-header-semantic-fail.stderr
@@ -71,73 +71,75 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:46:18
+  --> $DIR/fn-header-semantic-fail.rs:46:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 LL |         async fn fe1();
-   |                  ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe1();
-   |         ~~
+   |         ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:47:19
+  --> $DIR/fn-header-semantic-fail.rs:47:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 LL |         async fn fe1();
 LL |         unsafe fn fe2();
-   |                   ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe2();
-   |         ~~
+   |         ^^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:48:18
+  --> $DIR/fn-header-semantic-fail.rs:48:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         const fn fe3();
-   |                  ^^^
-   |
-help: remove the qualifiers
-   |
-LL |         fn fe3();
-   |         ~~
+   |         ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:49:23
+  --> $DIR/fn-header-semantic-fail.rs:49:9
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         extern "C" fn fe4();
-   |                       ^^^
-   |
-help: remove the qualifiers
+   |         ^^^^^^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:21
    |
-LL |         fn fe4();
-   |         ~~
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |                     ^^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:50:42
+  --> $DIR/fn-header-semantic-fail.rs:50:15
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
 ...
 LL |         const async unsafe extern "C" fn fe5();
-   |                                          ^^^
+   |               ^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:9
    |
-help: remove the qualifiers
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |         ^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:28
    |
-LL |         fn fe5();
-   |         ~~
+LL |     extern "C" {
+   |     ---------- in this `extern` block
+...
+LL |         const async unsafe extern "C" fn fe5();
+   |                            ^^^^^^^^^^ help: remove this qualifier
 
 error: functions cannot be both `const` and `async`
   --> $DIR/fn-header-semantic-fail.rs:50:9
@@ -148,6 +150,6 @@ LL |         const async unsafe extern "C" fn fe5();
    |         |     `async` because of this
    |         `const` because of this
 
-error: aborting due to 14 previous errors
+error: aborting due to 17 previous errors
 
 For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs
index 1993124edc3..d6c578681cc 100644
--- a/tests/ui/parser/no-const-fn-in-extern-block.rs
+++ b/tests/ui/parser/no-const-fn-in-extern-block.rs
@@ -3,6 +3,7 @@ extern "C" {
     //~^ ERROR functions in `extern` blocks cannot have qualifiers
     const unsafe fn bar();
     //~^ ERROR functions in `extern` blocks cannot have qualifiers
+    //~| ERROR functions in `extern` blocks cannot have qualifiers
 }
 
 fn main() {}
diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr
index 4ac0e265501..948ce669112 100644
--- a/tests/ui/parser/no-const-fn-in-extern-block.stderr
+++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr
@@ -1,29 +1,28 @@
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/no-const-fn-in-extern-block.rs:2:14
+  --> $DIR/no-const-fn-in-extern-block.rs:2:5
    |
 LL | extern "C" {
    | ---------- in this `extern` block
 LL |     const fn foo();
-   |              ^^^
-   |
-help: remove the qualifiers
-   |
-LL |     fn foo();
-   |     ~~
+   |     ^^^^^ help: remove this qualifier
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/no-const-fn-in-extern-block.rs:4:21
+  --> $DIR/no-const-fn-in-extern-block.rs:4:11
    |
 LL | extern "C" {
    | ---------- in this `extern` block
 ...
 LL |     const unsafe fn bar();
-   |                     ^^^
-   |
-help: remove the qualifiers
+   |           ^^^^^^ help: remove this qualifier
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/no-const-fn-in-extern-block.rs:4:5
    |
-LL |     fn bar();
-   |     ~~
+LL | extern "C" {
+   | ---------- in this `extern` block
+...
+LL |     const unsafe fn bar();
+   |     ^^^^^ help: remove this qualifier
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr
index 7cc2de141ae..fc05184f018 100644
--- a/tests/ui/parser/unsafe-foreign-mod-2.stderr
+++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr
@@ -11,18 +11,13 @@ LL | extern "C" unsafe {
    |            ^^^^^^
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/unsafe-foreign-mod-2.rs:4:15
+  --> $DIR/unsafe-foreign-mod-2.rs:4:5
    |
 LL | extern "C" unsafe {
    | ----------------- in this `extern` block
 ...
 LL |     unsafe fn foo();
-   |               ^^^
-   |
-help: remove the qualifiers
-   |
-LL |     fn foo();
-   |     ~~
+   |     ^^^^^^ help: remove this qualifier
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs
index 199d097336a..45ef6922d28 100644
--- a/tests/ui/proc-macro/auxiliary/api/mod.rs
+++ b/tests/ui/proc-macro/auxiliary/api/mod.rs
@@ -5,8 +5,6 @@
 #![crate_type = "proc-macro"]
 #![crate_name = "proc_macro_api_tests"]
 #![feature(proc_macro_span)]
-#![feature(proc_macro_byte_character)]
-#![feature(proc_macro_c_str_literals)]
 #![deny(dead_code)] // catch if a test function is never called
 
 extern crate proc_macro;
diff --git a/tests/ui/unpretty/hir-tree.rs b/tests/ui/unpretty/hir-tree.rs
new file mode 100644
index 00000000000..3388c60c425
--- /dev/null
+++ b/tests/ui/unpretty/hir-tree.rs
@@ -0,0 +1,10 @@
+//@ build-pass
+//@ compile-flags: -o - -Zunpretty=hir-tree
+//@ check-stdout
+//@ dont-check-compiler-stdout
+//@ dont-check-compiler-stderr
+//@ regex-error-pattern: Hello, Rustaceans!
+
+fn main() {
+    println!("Hello, Rustaceans!");
+}