diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index d34c289887e12..284bc74d5c434 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1519,7 +1519,7 @@ extern "C" {
 
 #[link(name = "llvm-wrapper", kind = "static")]
 extern "C" {
-    pub fn LLVMRustInstallFatalErrorHandler();
+    pub fn LLVMRustInstallErrorHandlers();
     pub fn LLVMRustDisableSystemDialogsOnCrash();
 
     // Create and destroy contexts.
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e32c38644aafb..c9e62e504aef1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -49,7 +49,7 @@ unsafe fn configure_llvm(sess: &Session) {
     let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
-    llvm::LLVMRustInstallFatalErrorHandler();
+    llvm::LLVMRustInstallErrorHandlers();
     // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
     // box for the purpose of launching a debugger. However, on CI this will
     // cause it to hang until it times out, which can take several hours.
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index a0be1c09c9a3d..e2010ab3830ac 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -5,49 +5,11 @@ use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_errors::{add_elided_lifetime_in_path_suggestion, Diag};
 use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_middle::middle::stability;
-use rustc_session::config::ExpectedValues;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::Session;
-use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::symbol::{sym, Symbol};
 use rustc_span::BytePos;
 
-const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
-
-fn check_cfg_expected_note(
-    sess: &Session,
-    possibilities: &[Symbol],
-    type_: &str,
-    name: Option<Symbol>,
-    suffix: &str,
-) -> String {
-    use std::fmt::Write;
-
-    let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
-        possibilities.len()
-    } else {
-        std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
-    };
-
-    let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
-    possibilities.sort();
-
-    let and_more = possibilities.len().saturating_sub(n_possibilities);
-    let possibilities = possibilities[..n_possibilities].join("`, `");
-
-    let mut note = String::with_capacity(50 + possibilities.len());
-
-    write!(&mut note, "expected {type_}").unwrap();
-    if let Some(name) = name {
-        write!(&mut note, " for `{name}`").unwrap();
-    }
-    write!(&mut note, " are: {suffix}`{possibilities}`").unwrap();
-    if and_more > 0 {
-        write!(&mut note, " and {and_more} more").unwrap();
-    }
-
-    note
-}
+mod check_cfg;
 
 pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) {
     match diagnostic {
@@ -219,242 +181,11 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
             diag.help(help);
             diag.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
         }
-        BuiltinLintDiag::UnexpectedCfgName((name, name_span), value) => {
-            #[allow(rustc::potential_query_instability)]
-            let possibilities: Vec<Symbol> =
-                sess.psess.check_config.expecteds.keys().copied().collect();
-
-            let mut names_possibilities: Vec<_> = if value.is_none() {
-                // We later sort and display all the possibilities, so the order here does not matter.
-                #[allow(rustc::potential_query_instability)]
-                sess.psess
-                    .check_config
-                    .expecteds
-                    .iter()
-                    .filter_map(|(k, v)| match v {
-                        ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
-                        _ => None,
-                    })
-                    .collect()
-            } else {
-                Vec::new()
-            };
-
-            let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
-            let mut is_feature_cfg = name == sym::feature;
-
-            if is_feature_cfg && is_from_cargo {
-                diag.help("consider defining some features in `Cargo.toml`");
-            // Suggest the most probable if we found one
-            } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
-                if let Some(ExpectedValues::Some(best_match_values)) =
-                    sess.psess.check_config.expecteds.get(&best_match)
-                {
-                    // We will soon sort, so the initial order does not matter.
-                    #[allow(rustc::potential_query_instability)]
-                    let mut possibilities =
-                        best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
-                    possibilities.sort();
-
-                    let mut should_print_possibilities = true;
-                    if let Some((value, value_span)) = value {
-                        if best_match_values.contains(&Some(value)) {
-                            diag.span_suggestion(
-                                name_span,
-                                "there is a config with a similar name and value",
-                                best_match,
-                                Applicability::MaybeIncorrect,
-                            );
-                            should_print_possibilities = false;
-                        } else if best_match_values.contains(&None) {
-                            diag.span_suggestion(
-                                name_span.to(value_span),
-                                "there is a config with a similar name and no value",
-                                best_match,
-                                Applicability::MaybeIncorrect,
-                            );
-                            should_print_possibilities = false;
-                        } else if let Some(first_value) = possibilities.first() {
-                            diag.span_suggestion(
-                                name_span.to(value_span),
-                                "there is a config with a similar name and different values",
-                                format!("{best_match} = \"{first_value}\""),
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            diag.span_suggestion(
-                                name_span.to(value_span),
-                                "there is a config with a similar name and different values",
-                                best_match,
-                                Applicability::MaybeIncorrect,
-                            );
-                        };
-                    } else {
-                        diag.span_suggestion(
-                            name_span,
-                            "there is a config with a similar name",
-                            best_match,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-
-                    if !possibilities.is_empty() && should_print_possibilities {
-                        let possibilities = possibilities.join("`, `");
-                        diag.help(format!(
-                            "expected values for `{best_match}` are: `{possibilities}`"
-                        ));
-                    }
-                } else {
-                    diag.span_suggestion(
-                        name_span,
-                        "there is a config with a similar name",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-
-                is_feature_cfg |= best_match == sym::feature;
-            } else {
-                if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
-                    names_possibilities.sort();
-                    for cfg_name in names_possibilities.iter() {
-                        diag.span_suggestion(
-                            name_span,
-                            "found config with similar value",
-                            format!("{cfg_name} = \"{name}\""),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-                if !possibilities.is_empty() {
-                    diag.help_once(check_cfg_expected_note(
-                        sess,
-                        &possibilities,
-                        "names",
-                        None,
-                        "",
-                    ));
-                }
-            }
-
-            let inst = if let Some((value, _value_span)) = value {
-                let pre = if is_from_cargo { "\\" } else { "" };
-                format!("cfg({name}, values({pre}\"{value}{pre}\"))")
-            } else {
-                format!("cfg({name})")
-            };
-
-            if is_from_cargo {
-                if !is_feature_cfg {
-                    diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
-                }
-                diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
-            } else {
-                diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-                diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
-            }
+        BuiltinLintDiag::UnexpectedCfgName(name, value) => {
+            check_cfg::unexpected_cfg_name(sess, diag, name, value)
         }
-        BuiltinLintDiag::UnexpectedCfgValue((name, name_span), value) => {
-            let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name)
-            else {
-                bug!(
-                    "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
-                );
-            };
-            let mut have_none_possibility = false;
-            // We later sort possibilities if it is not empty, so the
-            // order here does not matter.
-            #[allow(rustc::potential_query_instability)]
-            let possibilities: Vec<Symbol> = values
-                .iter()
-                .inspect(|a| have_none_possibility |= a.is_none())
-                .copied()
-                .flatten()
-                .collect();
-            let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
-
-            // Show the full list if all possible values for a given name, but don't do it
-            // for names as the possibilities could be very long
-            if !possibilities.is_empty() {
-                diag.note(check_cfg_expected_note(
-                    sess,
-                    &possibilities,
-                    "values",
-                    Some(name),
-                    if have_none_possibility { "(none), " } else { "" },
-                ));
-
-                if let Some((value, value_span)) = value {
-                    // Suggest the most probable if we found one
-                    if let Some(best_match) = find_best_match_for_name(&possibilities, value, None)
-                    {
-                        diag.span_suggestion(
-                            value_span,
-                            "there is a expected value with a similar name",
-                            format!("\"{best_match}\""),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                } else if let &[first_possibility] = &possibilities[..] {
-                    diag.span_suggestion(
-                        name_span.shrink_to_hi(),
-                        "specify a config value",
-                        format!(" = \"{first_possibility}\""),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            } else if have_none_possibility {
-                diag.note(format!("no expected value for `{name}`"));
-                if let Some((_value, value_span)) = value {
-                    diag.span_suggestion(
-                        name_span.shrink_to_hi().to(value_span),
-                        "remove the value",
-                        "",
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            } else {
-                diag.note(format!("no expected values for `{name}`"));
-
-                let sp = if let Some((_value, value_span)) = value {
-                    name_span.to(value_span)
-                } else {
-                    name_span
-                };
-                diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
-            }
-
-            // We don't want to suggest adding values to well known names
-            // since those are defined by rustc it-self. Users can still
-            // do it if they want, but should not encourage them.
-            let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
-
-            let inst = if let Some((value, _value_span)) = value {
-                let pre = if is_from_cargo { "\\" } else { "" };
-                format!("cfg({name}, values({pre}\"{value}{pre}\"))")
-            } else {
-                format!("cfg({name})")
-            };
-
-            if is_from_cargo {
-                if name == sym::feature {
-                    if let Some((value, _value_span)) = value {
-                        diag.help(format!(
-                            "consider adding `{value}` as a feature in `Cargo.toml`"
-                        ));
-                    } else {
-                        diag.help("consider defining some features in `Cargo.toml`");
-                    }
-                } else if !is_cfg_a_well_know_name {
-                    diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
-                }
-                diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
-            } else {
-                if !is_cfg_a_well_know_name {
-                    diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-                }
-                diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
-            }
+        BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
+            check_cfg::unexpected_cfg_value(sess, diag, name, value)
         }
         BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => {
             let left_sp = diag.span.primary_span().unwrap();
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
new file mode 100644
index 0000000000000..2c9a3a6d1b250
--- /dev/null
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -0,0 +1,277 @@
+use rustc_errors::{Applicability, Diag};
+use rustc_session::{config::ExpectedValues, Session};
+use rustc_span::edit_distance::find_best_match_for_name;
+use rustc_span::{sym, Span, Symbol};
+
+const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
+
+fn check_cfg_expected_note(
+    sess: &Session,
+    possibilities: &[Symbol],
+    type_: &str,
+    name: Option<Symbol>,
+    suffix: &str,
+) -> String {
+    use std::fmt::Write;
+
+    let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
+        possibilities.len()
+    } else {
+        std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
+    };
+
+    let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
+    possibilities.sort();
+
+    let and_more = possibilities.len().saturating_sub(n_possibilities);
+    let possibilities = possibilities[..n_possibilities].join("`, `");
+
+    let mut note = String::with_capacity(50 + possibilities.len());
+
+    write!(&mut note, "expected {type_}").unwrap();
+    if let Some(name) = name {
+        write!(&mut note, " for `{name}`").unwrap();
+    }
+    write!(&mut note, " are: {suffix}`{possibilities}`").unwrap();
+    if and_more > 0 {
+        write!(&mut note, " and {and_more} more").unwrap();
+    }
+
+    note
+}
+
+pub(super) fn unexpected_cfg_name(
+    sess: &Session,
+    diag: &mut Diag<'_, ()>,
+    (name, name_span): (Symbol, Span),
+    value: Option<(Symbol, Span)>,
+) {
+    #[allow(rustc::potential_query_instability)]
+    let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
+
+    let mut names_possibilities: Vec<_> = if value.is_none() {
+        // We later sort and display all the possibilities, so the order here does not matter.
+        #[allow(rustc::potential_query_instability)]
+        sess.psess
+            .check_config
+            .expecteds
+            .iter()
+            .filter_map(|(k, v)| match v {
+                ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
+                _ => None,
+            })
+            .collect()
+    } else {
+        Vec::new()
+    };
+
+    let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
+    let mut is_feature_cfg = name == sym::feature;
+
+    if is_feature_cfg && is_from_cargo {
+        diag.help("consider defining some features in `Cargo.toml`");
+    // Suggest the most probable if we found one
+    } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
+        if let Some(ExpectedValues::Some(best_match_values)) =
+            sess.psess.check_config.expecteds.get(&best_match)
+        {
+            // We will soon sort, so the initial order does not matter.
+            #[allow(rustc::potential_query_instability)]
+            let mut possibilities =
+                best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
+            possibilities.sort();
+
+            let mut should_print_possibilities = true;
+            if let Some((value, value_span)) = value {
+                if best_match_values.contains(&Some(value)) {
+                    diag.span_suggestion(
+                        name_span,
+                        "there is a config with a similar name and value",
+                        best_match,
+                        Applicability::MaybeIncorrect,
+                    );
+                    should_print_possibilities = false;
+                } else if best_match_values.contains(&None) {
+                    diag.span_suggestion(
+                        name_span.to(value_span),
+                        "there is a config with a similar name and no value",
+                        best_match,
+                        Applicability::MaybeIncorrect,
+                    );
+                    should_print_possibilities = false;
+                } else if let Some(first_value) = possibilities.first() {
+                    diag.span_suggestion(
+                        name_span.to(value_span),
+                        "there is a config with a similar name and different values",
+                        format!("{best_match} = \"{first_value}\""),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    diag.span_suggestion(
+                        name_span.to(value_span),
+                        "there is a config with a similar name and different values",
+                        best_match,
+                        Applicability::MaybeIncorrect,
+                    );
+                };
+            } else {
+                diag.span_suggestion(
+                    name_span,
+                    "there is a config with a similar name",
+                    best_match,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            if !possibilities.is_empty() && should_print_possibilities {
+                let possibilities = possibilities.join("`, `");
+                diag.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+            }
+        } else {
+            diag.span_suggestion(
+                name_span,
+                "there is a config with a similar name",
+                best_match,
+                Applicability::MaybeIncorrect,
+            );
+        }
+
+        is_feature_cfg |= best_match == sym::feature;
+    } else {
+        if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
+            names_possibilities.sort();
+            for cfg_name in names_possibilities.iter() {
+                diag.span_suggestion(
+                    name_span,
+                    "found config with similar value",
+                    format!("{cfg_name} = \"{name}\""),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+        if !possibilities.is_empty() {
+            diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, ""));
+        }
+    }
+
+    let inst = if let Some((value, _value_span)) = value {
+        let pre = if is_from_cargo { "\\" } else { "" };
+        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
+    } else {
+        format!("cfg({name})")
+    };
+
+    if is_from_cargo {
+        if !is_feature_cfg {
+            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+        }
+        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
+    } else {
+        diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
+        diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
+    }
+}
+
+pub(super) fn unexpected_cfg_value(
+    sess: &Session,
+    diag: &mut Diag<'_, ()>,
+    (name, name_span): (Symbol, Span),
+    value: Option<(Symbol, Span)>,
+) {
+    let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
+        bug!(
+            "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
+        );
+    };
+    let mut have_none_possibility = false;
+    // We later sort possibilities if it is not empty, so the
+    // order here does not matter.
+    #[allow(rustc::potential_query_instability)]
+    let possibilities: Vec<Symbol> = values
+        .iter()
+        .inspect(|a| have_none_possibility |= a.is_none())
+        .copied()
+        .flatten()
+        .collect();
+    let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
+
+    // Show the full list if all possible values for a given name, but don't do it
+    // for names as the possibilities could be very long
+    if !possibilities.is_empty() {
+        diag.note(check_cfg_expected_note(
+            sess,
+            &possibilities,
+            "values",
+            Some(name),
+            if have_none_possibility { "(none), " } else { "" },
+        ));
+
+        if let Some((value, value_span)) = value {
+            // Suggest the most probable if we found one
+            if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+                diag.span_suggestion(
+                    value_span,
+                    "there is a expected value with a similar name",
+                    format!("\"{best_match}\""),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        } else if let &[first_possibility] = &possibilities[..] {
+            diag.span_suggestion(
+                name_span.shrink_to_hi(),
+                "specify a config value",
+                format!(" = \"{first_possibility}\""),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    } else if have_none_possibility {
+        diag.note(format!("no expected value for `{name}`"));
+        if let Some((_value, value_span)) = value {
+            diag.span_suggestion(
+                name_span.shrink_to_hi().to(value_span),
+                "remove the value",
+                "",
+                Applicability::MaybeIncorrect,
+            );
+        }
+    } else {
+        diag.note(format!("no expected values for `{name}`"));
+
+        let sp = if let Some((_value, value_span)) = value {
+            name_span.to(value_span)
+        } else {
+            name_span
+        };
+        diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
+    }
+
+    // We don't want to suggest adding values to well known names
+    // since those are defined by rustc it-self. Users can still
+    // do it if they want, but should not encourage them.
+    let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
+
+    let inst = if let Some((value, _value_span)) = value {
+        let pre = if is_from_cargo { "\\" } else { "" };
+        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
+    } else {
+        format!("cfg({name})")
+    };
+
+    if is_from_cargo {
+        if name == sym::feature {
+            if let Some((value, _value_span)) = value {
+                diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+            } else {
+                diag.help("consider defining some features in `Cargo.toml`");
+            }
+        } else if !is_cfg_a_well_know_name {
+            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+        }
+        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
+    } else {
+        if !is_cfg_a_well_know_name {
+            diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
+        }
+        diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
+    }
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 1632b9e124905..91f54da5c12f7 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -25,6 +25,13 @@
 
 #include <iostream>
 
+// for raw `write` in the bad-alloc handler
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
 //===----------------------------------------------------------------------===
 //
 // This file defines alternate interfaces to core functions that are more
@@ -88,8 +95,24 @@ static void FatalErrorHandler(void *UserData,
   exit(101);
 }
 
-extern "C" void LLVMRustInstallFatalErrorHandler() {
+// Custom error handler for bad-alloc LLVM errors.
+//
+// It aborts the process without any further allocations, similar to LLVM's
+// default except that may be configured to `throw std::bad_alloc()` instead.
+static void BadAllocErrorHandler(void *UserData,
+                                 const char* Reason,
+                                 bool GenCrashDiag) {
+  const char *OOM = "rustc-LLVM ERROR: out of memory\n";
+  (void)!::write(2, OOM, strlen(OOM));
+  (void)!::write(2, Reason, strlen(Reason));
+  (void)!::write(2, "\n", 1);
+  abort();
+}
+
+extern "C" void LLVMRustInstallErrorHandlers() {
+  install_bad_alloc_error_handler(BadAllocErrorHandler);
   install_fatal_error_handler(FatalErrorHandler);
+  install_out_of_memory_new_handler();
 }
 
 extern "C" void LLVMRustDisableSystemDialogsOnCrash() {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 9b786feba8988..6473f772e304b 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -112,6 +112,7 @@
 //
 // Library features:
 // tidy-alphabetical-start
+#![feature(array_ptr_get)]
 #![feature(char_indices_offset)]
 #![feature(const_align_of_val)]
 #![feature(const_align_of_val_raw)]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index a0c04d3f65dfd..979fd1e4b4a2a 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1798,6 +1798,46 @@ impl<T> *const [T] {
     }
 }
 
+impl<T, const N: usize> *const [T; N] {
+    /// Returns a raw pointer to the array's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*const T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(array_ptr_get)]
+    /// use std::ptr;
+    ///
+    /// let arr: *const [i8; 3] = ptr::null();
+    /// assert_eq!(arr.as_ptr(), ptr::null());
+    /// ```
+    #[inline]
+    #[unstable(feature = "array_ptr_get", issue = "119834")]
+    #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
+    pub const fn as_ptr(self) -> *const T {
+        self as *const T
+    }
+
+    /// Returns a raw pointer to a slice containing the entire array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_ptr_get, slice_ptr_len)]
+    ///
+    /// let arr: *const [i32; 3] = &[1, 2, 4] as *const [i32; 3];
+    /// let slice: *const [i32] = arr.as_slice();
+    /// assert_eq!(slice.len(), 3);
+    /// ```
+    #[inline]
+    #[unstable(feature = "array_ptr_get", issue = "119834")]
+    #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
+    pub const fn as_slice(self) -> *const [T] {
+        self
+    }
+}
+
 // Equality for pointers
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *const T {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 6a9033a144deb..bfdd9dba320d3 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -2209,6 +2209,49 @@ impl<T> *mut [T] {
     }
 }
 
+impl<T, const N: usize> *mut [T; N] {
+    /// Returns a raw pointer to the array's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*mut T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(array_ptr_get)]
+    /// use std::ptr;
+    ///
+    /// let arr: *mut [i8; 3] = ptr::null_mut();
+    /// assert_eq!(arr.as_mut_ptr(), ptr::null_mut());
+    /// ```
+    #[inline]
+    #[unstable(feature = "array_ptr_get", issue = "119834")]
+    #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
+    pub const fn as_mut_ptr(self) -> *mut T {
+        self as *mut T
+    }
+
+    /// Returns a raw pointer to a mutable slice containing the entire array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_ptr_get)]
+    ///
+    /// let mut arr = [1, 2, 5];
+    /// let ptr: *mut [i32; 3] = &mut arr;
+    /// unsafe {
+    ///     (&mut *ptr.as_mut_slice())[..2].copy_from_slice(&[3, 4]);
+    /// }
+    /// assert_eq!(arr, [3, 4, 5]);
+    /// ```
+    #[inline]
+    #[unstable(feature = "array_ptr_get", issue = "119834")]
+    #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
+    pub const fn as_mut_slice(self) -> *mut [T] {
+        self
+    }
+}
+
 // Equality for pointers
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *mut T {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c5a7e87c4aa4f..421062f5873cd 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -1,5 +1,6 @@
 #![feature(alloc_layout_extra)]
 #![feature(array_chunks)]
+#![feature(array_ptr_get)]
 #![feature(array_windows)]
 #![feature(ascii_char)]
 #![feature(ascii_char_variants)]
@@ -52,6 +53,7 @@
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
+#![feature(slice_ptr_len)]
 #![feature(slice_split_once)]
 #![feature(split_as_slice)]
 #![feature(maybe_uninit_fill)]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 659fbd255c168..5c518e2d59340 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -1141,3 +1141,16 @@ fn test_const_copy() {
         assert!(*ptr2 == 1);
     };
 }
+
+#[test]
+fn test_null_array_as_slice() {
+    let arr: *mut [u8; 4] = null_mut();
+    let ptr: *mut [u8] = arr.as_mut_slice();
+    assert!(ptr.is_null());
+    assert_eq!(ptr.len(), 4);
+
+    let arr: *const [u8; 4] = null();
+    let ptr: *const [u8] = arr.as_slice();
+    assert!(ptr.is_null());
+    assert_eq!(ptr.len(), 4);
+}
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 690e20fb6b978..6d3163b90b10c 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1548,6 +1548,10 @@ impl Step for MirOpt {
             })
         };
 
+        run(self.target);
+
+        // Run more targets with `--bless`. But we always run the host target first, since some
+        // tests use very specific `only` clauses that are not covered by the target set below.
         if builder.config.cmd.bless() {
             // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort,
             // but while we're at it we might as well flex our cross-compilation support. This
@@ -1566,8 +1570,6 @@ impl Step for MirOpt {
                 });
                 run(panic_abort_target);
             }
-        } else {
-            run(self.target);
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f427055728fd7..83c595ce2416e 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3734,36 +3734,42 @@ impl<'test> TestCx<'test> {
         debug!(?support_lib_deps);
         debug!(?support_lib_deps_deps);
 
-        let res = self.cmd2procres(
-            Command::new(&self.config.rustc_path)
-                .arg("-o")
-                .arg(&recipe_bin)
-                .arg(format!(
-                    "-Ldependency={}",
-                    &support_lib_path.parent().unwrap().to_string_lossy()
-                ))
-                .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
-                .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
-                .arg("--extern")
-                .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
-                .arg(&self.testpaths.file.join("rmake.rs"))
-                .env("TARGET", &self.config.target)
-                .env("PYTHON", &self.config.python)
-                .env("S", &src_root)
-                .env("RUST_BUILD_STAGE", &self.config.stage_id)
-                .env("RUSTC", cwd.join(&self.config.rustc_path))
-                .env("TMPDIR", &tmpdir)
-                .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
-                .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
-                .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
-                .env("LLVM_COMPONENTS", &self.config.llvm_components)
-                // We for sure don't want these tests to run in parallel, so make
-                // sure they don't have access to these vars if we run via `make`
-                // at the top level
-                .env_remove("MAKEFLAGS")
-                .env_remove("MFLAGS")
-                .env_remove("CARGO_MAKEFLAGS"),
-        );
+        let mut cmd = Command::new(&self.config.rustc_path);
+        cmd.arg("-o")
+            .arg(&recipe_bin)
+            .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy()))
+            .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
+            .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
+            .arg("--extern")
+            .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
+            .arg(&self.testpaths.file.join("rmake.rs"))
+            .env("TARGET", &self.config.target)
+            .env("PYTHON", &self.config.python)
+            .env("S", &src_root)
+            .env("RUST_BUILD_STAGE", &self.config.stage_id)
+            .env("RUSTC", cwd.join(&self.config.rustc_path))
+            .env("TMPDIR", &tmpdir)
+            .env("LD_LIB_PATH_ENVVAR", dylib_env_var())
+            .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
+            .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
+            .env("LLVM_COMPONENTS", &self.config.llvm_components)
+            // We for sure don't want these tests to run in parallel, so make
+            // sure they don't have access to these vars if we run via `make`
+            // at the top level
+            .env_remove("MAKEFLAGS")
+            .env_remove("MFLAGS")
+            .env_remove("CARGO_MAKEFLAGS");
+
+        if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
+            let mut stage0_sysroot = build_root.clone();
+            stage0_sysroot.push("stage0-sysroot");
+            debug!(?stage0_sysroot);
+            debug!(exists = stage0_sysroot.exists());
+
+            cmd.arg("--sysroot").arg(&stage0_sysroot);
+        }
+
+        let res = self.cmd2procres(&mut cmd);
         if !res.status.success() {
             self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res);
         }
diff --git a/triagebot.toml b/triagebot.toml
index 89ffb2f41bb67..515600793da58 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -515,6 +515,9 @@ cc = ["@Nadrieril"]
 message = "Some changes occurred in exhaustiveness checking"
 cc = ["@Nadrieril"]
 
+[mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"]
+cc = ["@Urgau"]
+
 [mentions."library/core/src/intrinsics/simd.rs"]
 message = """
 Some changes occurred to the platform-builtins intrinsics. Make sure the
@@ -699,6 +702,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 [mentions."src/doc/unstable-book/src/language-features/no-sanitize.md"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
+[mentions."src/doc/unstable-book/src/compiler-flags/check-cfg.md"]
+cc = ["@Urgau"]
+
 [mentions."tests/codegen/sanitizer"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
@@ -717,6 +723,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 [mentions."tests/ui/stack-protector"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
+[mentions."tests/ui/check-cfg"]
+cc = ["@Urgau"]
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"