about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/debugger.rs60
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs191
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs4
-rw-r--r--compiler/rustc_expand/src/base.rs23
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs28
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs19
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_macros/src/query.rs2
-rw-r--r--compiler/rustc_middle/src/middle/debugger_visualizer.rs8
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs6
-rw-r--r--compiler/rustc_passes/messages.ftl9
-rw-r--r--compiler/rustc_passes/src/check_attr.rs16
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs113
-rw-r--r--compiler/rustc_passes/src/errors.rs17
-rw-r--r--compiler/rustc_privacy/src/lib.rs22
-rw-r--r--compiler/rustc_resolve/src/ident.rs11
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/crt_objects.rs17
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs8
31 files changed, 329 insertions, 289 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
new file mode 100644
index 00000000000..56ff10be426
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
@@ -0,0 +1,60 @@
+use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};
+
+use super::prelude::*;
+
+pub(crate) struct DebuggerViualizerParser;
+
+impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
+    const PATH: &[Symbol] = &[sym::debugger_visualizer];
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
+    const TEMPLATE: AttributeTemplate = template!(
+        List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
+        "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
+    );
+
+    type Item = DebugVisualizer;
+    const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
+
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c {
+        let Some(l) = args.list() else {
+            cx.expected_list(args.span().unwrap_or(cx.attr_span));
+            return None;
+        };
+        let Some(single) = l.single() else {
+            cx.expected_single_argument(l.span);
+            return None;
+        };
+        let Some(mi) = single.meta_item() else {
+            cx.expected_name_value(single.span(), None);
+            return None;
+        };
+        let path = mi.path().word_sym();
+        let visualizer_type = match path {
+            Some(sym::natvis_file) => DebuggerVisualizerType::Natvis,
+            Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter,
+            _ => {
+                cx.expected_specific_argument(
+                    mi.path().span(),
+                    &[sym::natvis_file, sym::gdb_script_file],
+                );
+                return None;
+            }
+        };
+
+        let Some(path) = mi.args().name_value() else {
+            cx.expected_name_value(single.span(), path);
+            return None;
+        };
+
+        let Some(path) = path.value_as_str() else {
+            cx.expected_string_literal(path.value_span, Some(path.value_as_lit()));
+            return None;
+        };
+
+        Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 4ed13d239b9..8dbf4c0ef32 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -36,6 +36,7 @@ pub(crate) mod cfg_old;
 pub(crate) mod codegen_attrs;
 pub(crate) mod confusables;
 pub(crate) mod crate_level;
+pub(crate) mod debugger;
 pub(crate) mod deprecation;
 pub(crate) mod dummy;
 pub(crate) mod inline;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index de1ab5e9578..d7ccf3c7806 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -28,6 +28,7 @@ use crate::attributes::crate_level::{
     CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
     RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
 };
+use crate::attributes::debugger::DebuggerViualizerParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::dummy::DummyParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -163,6 +164,7 @@ attribute_parsers!(
         // tidy-alphabetical-start
         Combine<AllowConstFnUnstableParser>,
         Combine<AllowInternalUnstableParser>,
+        Combine<DebuggerViualizerParser>,
         Combine<ForceTargetFeatureParser>,
         Combine<LinkParser>,
         Combine<ReprParser>,
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 11be7041167..861227f7c2a 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -538,7 +538,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 
         // If the declaration has an associated instance, compute extra attributes based on that.
         if let Some(instance) = instance {
-            llfn_attrs_from_instance(cx, llfn, instance);
+            llfn_attrs_from_instance(
+                cx,
+                cx.tcx,
+                llfn,
+                &cx.tcx.codegen_instance_attrs(instance.def),
+                Some(instance),
+            );
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index df3e49279d9..abd63120397 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -5,15 +5,16 @@ use rustc_ast::expand::allocator::{
 };
 use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 use rustc_symbol_mangling::mangle_internal_symbol;
-use smallvec::SmallVec;
 
+use crate::attributes::llfn_attrs_from_instance;
 use crate::builder::SBuilder;
 use crate::declare::declare_simple_fn;
 use crate::llvm::{self, FALSE, TRUE, Type, Value};
-use crate::{SimpleCx, attributes, debuginfo, llvm_util};
+use crate::{SimpleCx, attributes, debuginfo};
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
@@ -149,18 +150,8 @@ fn create_wrapper_function(
         ty,
     );
 
-    let mut attrs = SmallVec::<[_; 2]>::new();
-
-    let target_cpu = llvm_util::target_cpu(tcx.sess);
-    let target_cpu_attr = llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu);
-
-    let tune_cpu_attr = llvm_util::tune_cpu(tcx.sess)
-        .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu));
-
-    attrs.push(target_cpu_attr);
-    attrs.extend(tune_cpu_attr);
-
-    attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
+    let attrs = CodegenFnAttrs::new();
+    llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None);
 
     let no_return = if no_return {
         // -> ! DIFlagNoReturn
@@ -171,12 +162,6 @@ fn create_wrapper_function(
         None
     };
 
-    if tcx.sess.must_emit_unwind_tables() {
-        let uwtable =
-            attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
-        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
-    }
-
     let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
     let mut bx = SBuilder::build(&cx, llbb);
 
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index dcf6b945497..8070ea0b3e9 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -1,20 +1,21 @@
 //! Set and unset common attributes on LLVM values.
-use rustc_codegen_ssa::traits::*;
 use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_hir::def_id::DefId;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
+use rustc_middle::middle::codegen_fn_attrs::{
+    CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
+};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
 use rustc_symbol_mangling::mangle_internal_symbol;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
 
-use crate::context::CodegenCx;
+use crate::context::SimpleCx;
 use crate::errors::SanitizerMemtagRequiresMte;
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
 use crate::value::Value;
-use crate::{attributes, llvm_util};
+use crate::{Session, attributes, llvm_util};
 
 pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
     if !attrs.is_empty() {
@@ -30,18 +31,19 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
 
 /// Get LLVM attribute for the provided inline heuristic.
 pub(crate) fn inline_attr<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
 ) -> Option<&'ll Attribute> {
     // `optnone` requires `noinline`
-    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
     let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
         (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
-        (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
+        (InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint,
         (inline, _) => inline,
     };
 
-    if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
+    if !tcx.sess.opts.unstable_opts.inline_llvm {
         // disable LLVM inlining
         return Some(AttributeKind::NoInline.create_attr(cx.llcx));
     }
@@ -51,7 +53,7 @@ pub(crate) fn inline_attr<'ll, 'tcx>(
             Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
         }
         InlineAttr::Never => {
-            if cx.sess().target.arch != "amdgpu" {
+            if tcx.sess.target.arch != "amdgpu" {
                 Some(AttributeKind::NoInline.create_attr(cx.llcx))
             } else {
                 None
@@ -63,12 +65,13 @@ pub(crate) fn inline_attr<'ll, 'tcx>(
 
 #[inline]
 fn patchable_function_entry_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
     attr: Option<PatchableFunctionEntry>,
 ) -> SmallVec<[&'ll Attribute; 2]> {
     let mut attrs = SmallVec::new();
     let patchable_spec = attr.unwrap_or_else(|| {
-        PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry)
+        PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry)
     });
     let entry = patchable_spec.entry();
     let prefix = patchable_spec.prefix();
@@ -91,12 +94,13 @@ fn patchable_function_entry_attrs<'ll>(
 
 /// Get LLVM sanitize attributes.
 #[inline]
-pub(crate) fn sanitize_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+pub(crate) fn sanitize_attrs<'ll, 'tcx>(
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     no_sanitize: SanitizerSet,
 ) -> SmallVec<[&'ll Attribute; 4]> {
     let mut attrs = SmallVec::new();
-    let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
+    let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
     if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
         attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
     }
@@ -114,11 +118,11 @@ pub(crate) fn sanitize_attrs<'ll>(
     }
     if enabled.contains(SanitizerSet::MEMTAG) {
         // Check to make sure the mte target feature is actually enabled.
-        let features = cx.tcx.global_backend_features(());
+        let features = tcx.global_backend_features(());
         let mte_feature =
             features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
         if let None | Some("-mte") = mte_feature {
-            cx.tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
+            tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
         }
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
@@ -139,9 +143,12 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>)
     llvm::CreateUWTableAttr(llcx, async_unwind)
 }
 
-pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let mut fp = cx.sess().target.frame_pointer;
-    let opts = &cx.sess().opts;
+pub(crate) fn frame_pointer_type_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> Option<&'ll Attribute> {
+    let mut fp = sess.target.frame_pointer;
+    let opts = &sess.opts;
     // "mcount" function relies on stack pointer.
     // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
     if opts.unstable_opts.instrument_mcount {
@@ -156,8 +163,8 @@ pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'
     Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
 }
 
-fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let function_return_attr = match cx.sess().opts.unstable_opts.function_return {
+fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    let function_return_attr = match sess.opts.unstable_opts.function_return {
         FunctionReturn::Keep => return None,
         FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
     };
@@ -167,17 +174,20 @@ fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute>
 
 /// Tell LLVM what instrument function to insert.
 #[inline]
-fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> {
+fn instrument_function_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> SmallVec<[&'ll Attribute; 4]> {
     let mut attrs = SmallVec::new();
-    if cx.sess().opts.unstable_opts.instrument_mcount {
+    if sess.opts.unstable_opts.instrument_mcount {
         // Similar to `clang -pg` behavior. Handled by the
         // `post-inline-ee-instrument` LLVM pass.
 
         // The function name varies on platforms.
         // See test/CodeGen/mcount.c in clang.
-        let mcount_name = match &cx.sess().target.llvm_mcount_intrinsic {
+        let mcount_name = match &sess.target.llvm_mcount_intrinsic {
             Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
-            None => cx.sess().target.mcount.as_ref(),
+            None => sess.target.mcount.as_ref(),
         };
 
         attrs.push(llvm::CreateAttrStringValue(
@@ -186,7 +196,7 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr
             mcount_name,
         ));
     }
-    if let Some(options) = &cx.sess().opts.unstable_opts.instrument_xray {
+    if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
         // XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
         // Function prologue and epilogue are instrumented with NOP sleds,
         // a runtime library later replaces them with detours into tracing code.
@@ -217,20 +227,20 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr
     attrs
 }
 
-fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    if !cx.sess().opts.unstable_opts.no_jump_tables {
+fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    if !sess.opts.unstable_opts.no_jump_tables {
         return None;
     }
 
     Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
 }
 
-fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> {
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer and thread sanitizer. With asan we're already protected from
     // stack overflow anyway so we don't really need stack probes regardless.
-    if cx
-        .sess()
+    if tcx
+        .sess
         .opts
         .unstable_opts
         .sanitizer
@@ -240,22 +250,22 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     }
 
     // probestack doesn't play nice either with `-C profile-generate`.
-    if cx.sess().opts.cg.profile_generate.enabled() {
+    if tcx.sess.opts.cg.profile_generate.enabled() {
         return None;
     }
 
-    let attr_value = match cx.sess().target.stack_probes {
+    let attr_value = match tcx.sess.target.stack_probes {
         StackProbeType::None => return None,
         // Request LLVM to generate the probes inline. If the given LLVM version does not support
         // this, no probe is generated at all (even if the attribute is specified).
         StackProbeType::Inline => "inline-asm",
         // Flag our internal `__rust_probestack` function as the stack probe symbol.
         // This is defined in the `compiler-builtins` crate for each architecture.
-        StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
+        StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"),
         // Pick from the two above based on the LLVM version.
         StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
             if llvm_util::get_version() < min_llvm_version_for_inline {
-                &mangle_internal_symbol(cx.tcx, "__rust_probestack")
+                &mangle_internal_symbol(tcx, "__rust_probestack")
             } else {
                 "inline-asm"
             }
@@ -264,8 +274,8 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
 }
 
-fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let sspattr = match cx.sess().stack_protector() {
+fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    let sspattr = match sess.stack_protector() {
         StackProtector::None => return None,
         StackProtector::All => AttributeKind::StackProtectReq,
         StackProtector::Strong => AttributeKind::StackProtectStrong,
@@ -275,33 +285,34 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     Some(sspattr.create_attr(cx.llcx))
 }
 
-fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    if cx.sess().target.arch != "s390x" {
+fn backchain_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    if sess.target.arch != "s390x" {
         return None;
     }
 
-    let requested_features = cx.sess().opts.cg.target_feature.split(',');
+    let requested_features = sess.opts.cg.target_feature.split(',');
     let found_positive = requested_features.clone().any(|r| r == "+backchain");
 
     if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None }
 }
 
-pub(crate) fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute {
-    let target_cpu = llvm_util::target_cpu(cx.tcx.sess);
+pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
+    let target_cpu = llvm_util::target_cpu(sess);
     llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
 }
 
-pub(crate) fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    llvm_util::tune_cpu(cx.tcx.sess)
+pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    llvm_util::tune_cpu(sess)
         .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
 }
 
 /// Get the `target-features` LLVM attribute.
-pub(crate) fn target_features_attr<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+pub(crate) fn target_features_attr<'ll, 'tcx>(
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     function_features: Vec<String>,
 ) -> Option<&'ll Attribute> {
-    let global_features = cx.tcx.global_backend_features(()).iter().map(String::as_str);
+    let global_features = tcx.global_backend_features(()).iter().map(String::as_str);
     let function_features = function_features.iter().map(String::as_str);
     let target_features =
         global_features.chain(function_features).intersperse(",").collect::<String>();
@@ -311,22 +322,22 @@ pub(crate) fn target_features_attr<'ll>(
 
 /// Get the `NonLazyBind` LLVM attribute,
 /// if the codegen options allow skipping the PLT.
-pub(crate) fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+pub(crate) fn non_lazy_bind_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> Option<&'ll Attribute> {
     // Don't generate calls through PLT if it's not necessary
-    if !cx.sess().needs_plt() {
-        Some(AttributeKind::NonLazyBind.create_attr(cx.llcx))
-    } else {
-        None
-    }
+    if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None }
 }
 
 /// Get the default optimizations attrs for a function.
 #[inline]
 pub(crate) fn default_optimisation_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
 ) -> SmallVec<[&'ll Attribute; 2]> {
     let mut attrs = SmallVec::new();
-    match cx.sess().opts.optimize {
+    match sess.opts.optimize {
         OptLevel::Size => {
             attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
         }
@@ -347,17 +358,18 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
 /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
 /// attributes.
 pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     llfn: &'ll Value,
-    instance: ty::Instance<'tcx>,
+    codegen_fn_attrs: &CodegenFnAttrs,
+    instance: Option<ty::Instance<'tcx>>,
 ) {
-    let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
-
+    let sess = tcx.sess;
     let mut to_add = SmallVec::<[_; 16]>::new();
 
     match codegen_fn_attrs.optimize {
         OptimizeAttr::Default => {
-            to_add.extend(default_optimisation_attrs(cx));
+            to_add.extend(default_optimisation_attrs(cx, sess));
         }
         OptimizeAttr::DoNotOptimize => {
             to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
@@ -369,21 +381,21 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         OptimizeAttr::Speed => {}
     }
 
-    if cx.sess().must_emit_unwind_tables() {
-        to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind));
+    if sess.must_emit_unwind_tables() {
+        to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
     }
 
-    if cx.sess().opts.unstable_opts.profile_sample_use.is_some() {
+    if sess.opts.unstable_opts.profile_sample_use.is_some() {
         to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
     }
 
     // FIXME: none of these functions interact with source level attributes.
-    to_add.extend(frame_pointer_type_attr(cx));
-    to_add.extend(function_return_attr(cx));
-    to_add.extend(instrument_function_attr(cx));
-    to_add.extend(nojumptables_attr(cx));
-    to_add.extend(probestack_attr(cx));
-    to_add.extend(stackprotector_attr(cx));
+    to_add.extend(frame_pointer_type_attr(cx, sess));
+    to_add.extend(function_return_attr(cx, sess));
+    to_add.extend(instrument_function_attr(cx, sess));
+    to_add.extend(nojumptables_attr(cx, sess));
+    to_add.extend(probestack_attr(cx, tcx));
+    to_add.extend(stackprotector_attr(cx, sess));
 
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
         to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
@@ -404,13 +416,13 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         // not used.
     } else {
         // Do not set sanitizer attributes for naked functions.
-        to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
+        to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.no_sanitize));
 
         // For non-naked functions, set branch protection attributes on aarch64.
         if let Some(BranchProtection { bti, pac_ret, gcs }) =
-            cx.sess().opts.unstable_opts.branch_protection
+            sess.opts.unstable_opts.branch_protection
         {
-            assert!(cx.sess().target.arch == "aarch64");
+            assert!(sess.target.arch == "aarch64");
             if bti {
                 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
             }
@@ -438,14 +450,15 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
     {
         to_add.push(create_alloc_family_attr(cx.llcx));
-        if let Some(zv) =
-            cx.tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
+        if let Some(instance) = instance
+            && let Some(zv) =
+                tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
             && let Some(name) = zv.value_str()
         {
             to_add.push(llvm::CreateAttrStringValue(
                 cx.llcx,
                 "alloc-variant-zeroed",
-                &mangle_internal_symbol(cx.tcx, name.as_str()),
+                &mangle_internal_symbol(tcx, name.as_str()),
             ));
         }
         // apply to argument place instead of function
@@ -490,18 +503,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     if let Some(align) = codegen_fn_attrs.alignment {
         llvm::set_alignment(llfn, align);
     }
-    if let Some(backchain) = backchain_attr(cx) {
+    if let Some(backchain) = backchain_attr(cx, sess) {
         to_add.push(backchain);
     }
-    to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry));
+    to_add.extend(patchable_function_entry_attrs(
+        cx,
+        sess,
+        codegen_fn_attrs.patchable_function_entry,
+    ));
 
     // Always annotate functions with the target-cpu they are compiled for.
     // Without this, ThinLTO won't inline Rust functions into Clang generated
     // functions (because Clang annotates functions this way too).
-    to_add.push(target_cpu_attr(cx));
+    to_add.push(target_cpu_attr(cx, sess));
     // tune-cpu is only conveyed through the attribute for our purpose.
     // The target doesn't care; the subtarget reads our attribute.
-    to_add.extend(tune_cpu_attr(cx));
+    to_add.extend(tune_cpu_attr(cx, sess));
 
     let function_features =
         codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
@@ -509,7 +526,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     // Apply function attributes as per usual if there are no user defined
     // target features otherwise this will get applied at the callsite.
     if function_features.is_empty() {
-        if let Some(inline_attr) = inline_attr(cx, instance) {
+        if let Some(instance) = instance
+            && let Some(inline_attr) = inline_attr(cx, tcx, instance)
+        {
             to_add.push(inline_attr);
         }
     }
@@ -517,7 +536,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     let function_features = function_features
         .iter()
         // Convert to LLVMFeatures and filter out unavailable ones
-        .flat_map(|feat| llvm_util::to_llvm_features(cx.tcx.sess, feat))
+        .flat_map(|feat| llvm_util::to_llvm_features(sess, feat))
         // Convert LLVMFeatures & dependencies to +<feats>s
         .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}")))
         .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
@@ -526,20 +545,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         }))
         .collect::<Vec<String>>();
 
-    if cx.tcx.sess.target.is_like_wasm {
+    if sess.target.is_like_wasm {
         // If this function is an import from the environment but the wasm
         // import has a specific module/name, apply them here.
-        if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
+        if let Some(instance) = instance
+            && let Some(module) = wasm_import_module(tcx, instance.def_id())
+        {
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
 
             let name =
-                codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
+                codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id()));
             let name = name.as_str();
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
         }
     }
 
-    to_add.extend(target_features_attr(cx, function_features));
+    to_add.extend(target_features_attr(cx, tcx, function_features));
 
     attributes::apply_to_llfn(llfn, Function, &to_add);
 }
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 978134cc32b..6d12b511e9c 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -105,7 +105,7 @@ pub(crate) fn compile_codegen_unit(
             if let Some(entry) =
                 maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit)
             {
-                let attrs = attributes::sanitize_attrs(&cx, SanitizerSet::empty());
+                let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerSet::empty());
                 attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
             }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0f17cc9063a..a4dc4eb532f 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1433,7 +1433,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 // If there is an inline attribute and a target feature that matches
                 // we will add the attribute to the callsite otherwise we'll omit
                 // this and not add the attribute to prevent soundness issues.
-                && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance)
+                && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance)
                 && self.cx.tcx.is_target_feature_call_safe(
                     &fn_call_attrs.target_features,
                     &fn_defn_attrs.target_features,
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index b7d2241da47..aa5c17269fb 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -876,7 +876,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 } else {
                     let fty = self.type_variadic_func(&[], self.type_i32());
                     let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty);
-                    let target_cpu = attributes::target_cpu_attr(self);
+                    let target_cpu = attributes::target_cpu_attr(self, self.sess());
                     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[target_cpu]);
                     llfn
                 }
@@ -891,15 +891,15 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn set_frame_pointer_type(&self, llfn: &'ll Value) {
-        if let Some(attr) = attributes::frame_pointer_type_attr(self) {
+        if let Some(attr) = attributes::frame_pointer_type_attr(self, self.sess()) {
             attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[attr]);
         }
     }
 
     fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
         let mut attrs = SmallVec::<[_; 2]>::new();
-        attrs.push(attributes::target_cpu_attr(self));
-        attrs.extend(attributes::tune_cpu_attr(self));
+        attrs.push(attributes::target_cpu_attr(self, self.sess()));
+        attrs.extend(attributes::tune_cpu_attr(self, self.sess()));
         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
     }
 
@@ -918,7 +918,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             attributes::apply_to_llfn(
                 llfn,
                 llvm::AttributePlace::Function,
-                attributes::target_features_attr(self, vec![]).as_slice(),
+                attributes::target_features_attr(self, self.tcx, vec![]).as_slice(),
             );
             Some(llfn)
         } else {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 7a6dc008c7b..3081badb821 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -2,9 +2,9 @@
 
 use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
 use rustc_codegen_ssa::traits::*;
+use rustc_hir::attrs::DebuggerVisualizerType;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
-use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
 use rustc_session::config::{CrateType, DebugInfo};
 
 use crate::builder::Builder;
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 960a895a203..36cdb498839 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -76,7 +76,7 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
         attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
     }
 
-    attrs.extend(attributes::non_lazy_bind_attr(cx));
+    attrs.extend(attributes::non_lazy_bind_attr(cx, cx.tcx.sess));
 
     attributes::apply_to_llfn(llfn, Function, &attrs);
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 68a2f43ec67..422b06350e1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
 use rustc_data_structures::unord::UnordMap;
-use rustc_hir::attrs::OptimizeAttr;
+use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemId, Target};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
 use rustc_middle::middle::lang_items;
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 3956125bace..33b712e3aed 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -324,16 +324,16 @@ pub trait BangProcMacro {
 
 impl<F> BangProcMacro for F
 where
-    F: Fn(TokenStream) -> TokenStream,
+    F: Fn(&mut ExtCtxt<'_>, Span, TokenStream) -> Result<TokenStream, ErrorGuaranteed>,
 {
     fn expand<'cx>(
         &self,
-        _ecx: &'cx mut ExtCtxt<'_>,
-        _span: Span,
+        ecx: &'cx mut ExtCtxt<'_>,
+        span: Span,
         ts: TokenStream,
     ) -> Result<TokenStream, ErrorGuaranteed> {
         // FIXME setup implicit context in TLS before calling self.
-        Ok(self(ts))
+        self(ecx, span, ts)
     }
 }
 
@@ -999,17 +999,14 @@ impl SyntaxExtension {
 
     /// A dummy bang macro `foo!()`.
     pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
-        fn expander<'cx>(
-            cx: &'cx mut ExtCtxt<'_>,
+        fn expand(
+            ecx: &mut ExtCtxt<'_>,
             span: Span,
-            _: TokenStream,
-        ) -> MacroExpanderResult<'cx> {
-            ExpandResult::Ready(DummyResult::any(
-                span,
-                cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"),
-            ))
+            _ts: TokenStream,
+        ) -> Result<TokenStream, ErrorGuaranteed> {
+            Err(ecx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"))
         }
-        SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Arc::new(expander)), edition)
+        SyntaxExtension::default(SyntaxExtensionKind::Bang(Arc::new(expand)), edition)
     }
 
     /// A dummy derive macro `#[derive(Foo)]`.
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 4c0e0bbfe26..172bc3d1d9f 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -971,7 +971,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             });
                         }
                     },
-                    SyntaxExtensionKind::LegacyBang(..) => {
+                    SyntaxExtensionKind::Bang(..) => {
                         let msg = "expanded a dummy glob delegation";
                         let guar = self.cx.dcx().span_delayed_bug(span, msg);
                         return ExpandResult::Ready(fragment_kind.dummy(span, guar));
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 1d147a0385c..d4504ba720e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -33,8 +33,8 @@ use super::diagnostics::{FailedMacro, failed_to_match_macro};
 use super::macro_parser::{NamedMatches, NamedParseResult};
 use super::{SequenceRepetition, diagnostics};
 use crate::base::{
-    AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult,
-    SyntaxExtension, SyntaxExtensionKind, TTMacroExpander,
+    AttrProcMacro, BangProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult,
+    MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander,
 };
 use crate::errors;
 use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
@@ -267,16 +267,16 @@ impl AttrProcMacro for MacroRulesMacroExpander {
     }
 }
 
-struct DummyExpander(ErrorGuaranteed);
+struct DummyBang(ErrorGuaranteed);
 
-impl TTMacroExpander for DummyExpander {
+impl BangProcMacro for DummyBang {
     fn expand<'cx>(
         &self,
         _: &'cx mut ExtCtxt<'_>,
-        span: Span,
+        _: Span,
         _: TokenStream,
-    ) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> {
-        ExpandResult::Ready(DummyResult::any(span, self.0))
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        Err(self.0)
     }
 }
 
@@ -664,7 +664,7 @@ pub fn compile_declarative_macro(
         SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
     };
     let dummy_syn_ext =
-        |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0);
+        |guar| (mk_syn_ext(SyntaxExtensionKind::Bang(Arc::new(DummyBang(guar)))), 0);
 
     let macro_rules = macro_def.macro_rules;
     let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@@ -894,12 +894,12 @@ fn check_redundant_vis_repetition(
     seq: &SequenceRepetition,
     span: &DelimSpan,
 ) {
-    let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
-    let is_vis = seq.tts.first().map_or(false, |tt| {
-        matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
-    });
-
-    if is_vis && is_zero_or_one {
+    if seq.kleene.op == KleeneOp::ZeroOrOne
+        && matches!(
+            seq.tts.first(),
+            Some(mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
+        )
+    {
         err.note("a `vis` fragment can already be empty");
         err.multipart_suggestion(
             "remove the `$(` and `)?`",
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 5481c9debc1..ddcbaeaad88 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -363,6 +363,20 @@ pub struct LinkEntry {
     pub import_name_type: Option<(PeImportNameType, Span)>,
 }
 
+#[derive(HashStable_Generic, PrintAttribute)]
+#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+pub enum DebuggerVisualizerType {
+    Natvis,
+    GdbPrettyPrinter,
+}
+
+#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
+pub struct DebugVisualizer {
+    pub span: Span,
+    pub visualizer_type: DebuggerVisualizerType,
+    pub path: Symbol,
+}
+
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -485,7 +499,10 @@ pub enum AttributeKind {
     /// Represents `#[custom_mir]`.
     CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
 
-    ///Represents `#[rustc_deny_explicit_impl]`.
+    /// Represents `#[debugger_visualizer]`.
+    DebuggerVisualizer(ThinVec<DebugVisualizer>),
+
+    /// Represents `#[rustc_deny_explicit_impl]`.
     DenyExplicitImpl(Span),
 
     /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index e0a37f50f45..1611b865c77 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -37,6 +37,7 @@ impl AttributeKind {
             Coverage(..) => No,
             CrateName { .. } => No,
             CustomMir(_, _, _) => Yes,
+            DebuggerVisualizer(..) => No,
             DenyExplicitImpl(..) => No,
             Deprecation { .. } => Yes,
             DoNotImplementViaObject(..) => No,
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 5821ffa3a30..5d32950875a 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -5,7 +5,7 @@ use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::{
     AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced,
-    parenthesized, parse_macro_input, parse_quote, token,
+    parenthesized, parse_macro_input, token,
 };
 
 mod kw {
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 5a811321f58..a7f0095dcdf 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -1,15 +1,9 @@
 use std::path::PathBuf;
 use std::sync::Arc;
 
+use rustc_hir::attrs::DebuggerVisualizerType;
 use rustc_macros::{Decodable, Encodable, HashStable};
 
-#[derive(HashStable)]
-#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
-pub enum DebuggerVisualizerType {
-    Natvis,
-    GdbPrettyPrinter,
-}
-
 /// A single debugger visualizer file.
 #[derive(HashStable)]
 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index cdb2c5561ce..7ca94e655fb 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -395,12 +395,10 @@ enum NeedsTemporary {
     Maybe,
 }
 
-///////////////////////////////////////////////////////////////////////////
 /// The `BlockAnd` "monad" packages up the new basic block along with a
 /// produced value (sometimes just unit, of course). The `unpack!`
 /// macro (and methods below) makes working with `BlockAnd` much more
 /// convenient.
-
 #[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
 struct BlockAnd<T>(BasicBlock, T);
 
@@ -438,9 +436,7 @@ macro_rules! unpack {
     }};
 }
 
-///////////////////////////////////////////////////////////////////////////
-/// the main entry point for building MIR for a function
-
+/// The main entry point for building MIR for a function.
 fn construct_fn<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_def: LocalDefId,
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 6cd68380e46..870e0a90b54 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -93,15 +93,6 @@ passes_dead_codes =
        }
     } never {$participle}
 
-passes_debug_visualizer_invalid =
-    invalid argument
-    .note_1 = expected: `natvis_file = "..."`
-    .note_2 = OR
-    .note_3 = expected: `gdb_script_file = "..."`
-
-passes_debug_visualizer_placement =
-    attribute should be applied to a module
-
 passes_debug_visualizer_unreadable =
     couldn't read {$file}: {$error}
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index aef123c3721..007353f136d 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -282,6 +282,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::ObjcClass { .. }
                     | AttributeKind::ObjcSelector { .. }
                     | AttributeKind::RustcCoherenceIsCore(..)
+                    | AttributeKind::DebuggerVisualizer(..)
                 ) => { /* do nothing  */ }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
@@ -302,7 +303,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             &mut doc_aliases,
                         ),
                         [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
-                        [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
                         [sym::rustc_no_implicit_autorefs, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
@@ -1783,20 +1783,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
-    fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
-        // Here we only check that the #[debugger_visualizer] attribute is attached
-        // to nothing other than a module. All other checks are done in the
-        // `debugger_visualizer` query where they need to be done for decoding
-        // anyway.
-        match target {
-            Target::Mod => {}
-            _ => {
-                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
-            }
-        }
-    }
-
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
     /// (Allows proc_macro functions)
     fn check_rustc_allow_const_fn_unstable(
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 7a7a8175e55..7211f3cf85b 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -1,67 +1,60 @@
 //! Detecting usage of the `#[debugger_visualizer]` attribute.
 
-use rustc_ast::Attribute;
+use rustc_ast::ast::NodeId;
+use rustc_ast::{HasNodeId, ItemKind, ast};
+use rustc_attr_parsing::AttributeParser;
 use rustc_expand::base::resolve_path;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_hir::Attribute;
+use rustc_hir::attrs::{AttributeKind, DebugVisualizer};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::sym;
+use rustc_span::{DUMMY_SP, Span, sym};
 
-use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
+use crate::errors::DebugVisualizerUnreadable;
 
 impl DebuggerVisualizerCollector<'_> {
-    fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
-        if attr.has_name(sym::debugger_visualizer) {
-            let Some(hints) = attr.meta_item_list() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
+    fn check_for_debugger_visualizer(
+        &mut self,
+        attrs: &[ast::Attribute],
+        span: Span,
+        node_id: NodeId,
+    ) {
+        if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
+            AttributeParser::parse_limited(
+                &self.sess,
+                attrs,
+                sym::debugger_visualizer,
+                span,
+                node_id,
+                None,
+            )
+        {
+            for DebugVisualizer { span, visualizer_type, path } in visualizers {
+                let file = match resolve_path(&self.sess, path.as_str(), span) {
+                    Ok(file) => file,
+                    Err(err) => {
+                        err.emit();
+                        return;
+                    }
+                };
 
-            let [hint] = hints.as_slice() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
-
-            let Some(meta_item) = hint.meta_item() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
-
-            let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
-            {
-                (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
-                (Some(sym::gdb_script_file), Some(value)) => {
-                    (DebuggerVisualizerType::GdbPrettyPrinter, value)
-                }
-                (_, _) => {
-                    self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
-                    return;
-                }
-            };
-
-            let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
-                Ok(file) => file,
-                Err(err) => {
-                    err.emit();
-                    return;
-                }
-            };
-
-            match self.sess.source_map().load_binary_file(&file) {
-                Ok((source, _)) => {
-                    self.visualizers.push(DebuggerVisualizerFile::new(
-                        source,
-                        visualizer_type,
-                        file,
-                    ));
-                }
-                Err(error) => {
-                    self.sess.dcx().emit_err(DebugVisualizerUnreadable {
-                        span: meta_item.span,
-                        file: &file,
-                        error,
-                    });
+                match self.sess.source_map().load_binary_file(&file) {
+                    Ok((source, _)) => {
+                        self.visualizers.push(DebuggerVisualizerFile::new(
+                            source,
+                            visualizer_type,
+                            file,
+                        ));
+                    }
+                    Err(error) => {
+                        self.sess.dcx().emit_err(DebugVisualizerUnreadable {
+                            span,
+                            file: &file,
+                            error,
+                        });
+                    }
                 }
             }
         }
@@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> {
 }
 
 impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
-    fn visit_attribute(&mut self, attr: &'ast Attribute) {
-        self.check_for_debugger_visualizer(attr);
-        rustc_ast::visit::walk_attribute(self, attr);
+    fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
+        if let ItemKind::Mod(..) = item.kind {
+            self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
+        }
+        rustc_ast::visit::walk_item(self, item);
+    }
+    fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
+        self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
+        rustc_ast::visit::walk_crate(self, krate);
     }
 }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cd8935f6b2f..cfd6b9e6dff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -476,23 +476,6 @@ pub(crate) struct MacroOnlyAttribute {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_placement)]
-pub(crate) struct DebugVisualizerPlacement {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_invalid)]
-#[note(passes_note_1)]
-#[note(passes_note_2)]
-#[note(passes_note_3)]
-pub(crate) struct DebugVisualizerInvalid {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_debug_visualizer_unreadable)]
 pub(crate) struct DebugVisualizerUnreadable<'a> {
     #[primary_span]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 1bddbd03cc3..c9dbb204f61 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -45,7 +45,7 @@ use tracing::debug;
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 ////////////////////////////////////////////////////////////////////////////////
-/// Generic infrastructure used to implement specific visitors below.
+// Generic infrastructure used to implement specific visitors below.
 ////////////////////////////////////////////////////////////////////////////////
 
 struct LazyDefPathStr<'tcx> {
@@ -309,10 +309,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
     if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
 }
 
-////////////////////////////////////////////////////////////////////////////////
 /// Visitor used to determine impl visibility and reachability.
-////////////////////////////////////////////////////////////////////////////////
-
 struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
     tcx: TyCtxt<'tcx>,
     effective_visibilities: &'a EffectiveVisibilities,
@@ -387,10 +384,7 @@ impl VisibilityLike for EffectiveVisibility {
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
 /// The embargo visitor, used to determine the exports of the AST.
-////////////////////////////////////////////////////////////////////////////////
-
 struct EmbargoVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 
@@ -849,9 +843,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
 /// Visitor, used for EffectiveVisibilities table checking
-////////////////////////////////////////////////////////////////////////////////
 pub struct TestReachabilityVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     effective_visibilities: &'a EffectiveVisibilities,
@@ -909,13 +901,11 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
     }
 }
 
-//////////////////////////////////////////////////////////////////////////////////////
 /// Name privacy visitor, checks privacy and reports violations.
+///
 /// Most of name privacy checks are performed during the main resolution phase,
 /// or later in type checking when field accesses and associated items are resolved.
 /// This pass performs remaining checks for fields in struct expressions and patterns.
-//////////////////////////////////////////////////////////////////////////////////////
-
 struct NamePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
@@ -1120,12 +1110,10 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////////////////
 /// Type privacy visitor, checks types for privacy and reports violations.
+///
 /// Both explicitly written types and inferred types of expressions and patterns are checked.
 /// Checks are performed on "semantic" types regardless of names and their hygiene.
-////////////////////////////////////////////////////////////////////////////////////////////
-
 struct TypePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     module_def_id: LocalModDefId,
@@ -1345,13 +1333,11 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////////
 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
 /// finds any private components in it.
+///
 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
 /// and traits in public interfaces.
-///////////////////////////////////////////////////////////////////////////////
-
 struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     item_def_id: LocalDefId,
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 35051675fd8..51489019950 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -492,14 +492,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         _ => Err(Determinacy::Determined),
                     },
                     Scope::Module(module, derive_fallback_lint_id) => {
-                        // FIXME: use `finalize_scope` here.
                         let (adjusted_parent_scope, adjusted_finalize) =
                             if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) {
-                                (parent_scope, finalize)
+                                (parent_scope, finalize_scope!())
                             } else {
                                 (
                                     &ParentScope { module, ..*parent_scope },
-                                    finalize.map(|f| Finalize { used: Used::Scope, ..f }),
+                                    finalize_scope!().map(|f| Finalize { used: Used::Scope, ..f }),
                                 )
                             };
                         let binding = this.reborrow().resolve_ident_in_module_unadjusted(
@@ -557,8 +556,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         None => Err(Determinacy::Determined),
                     },
                     Scope::ExternPreludeItems => {
-                        // FIXME: use `finalize_scope` here.
-                        match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) {
+                        match this
+                            .reborrow()
+                            .extern_prelude_get_item(ident, finalize_scope!().is_some())
+                        {
                             Some(binding) => {
                                 extern_prelude_item_binding = Some(binding);
                                 Ok((binding, Flags::empty()))
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index 4ba11021988..2867428e42f 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -93,10 +93,7 @@ pub(crate) fn opts() -> TargetOptions {
         binary_format: BinaryFormat::Coff,
         allows_weak_linkage: false,
         pre_link_args,
-        pre_link_objects: crt_objects::pre_mingw(),
-        post_link_objects: crt_objects::post_mingw(),
         pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(),
-        post_link_objects_self_contained: crt_objects::post_mingw_self_contained(),
         link_self_contained: LinkSelfContainedDefault::InferredForMingw,
         late_link_args,
         late_link_args_dynamic,
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index e3b6430a463..2d84e78f255 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -86,6 +86,17 @@ pub(super) fn post_musl_self_contained() -> CrtObjects {
 
 pub(super) fn pre_mingw_self_contained() -> CrtObjects {
     new(&[
+        (LinkOutputKind::DynamicNoPicExe, &["crt2.o"]),
+        (LinkOutputKind::DynamicPicExe, &["crt2.o"]),
+        (LinkOutputKind::StaticNoPicExe, &["crt2.o"]),
+        (LinkOutputKind::StaticPicExe, &["crt2.o"]),
+        (LinkOutputKind::DynamicDylib, &["dllcrt2.o"]),
+        (LinkOutputKind::StaticDylib, &["dllcrt2.o"]),
+    ])
+}
+
+pub(super) fn pre_i686_mingw_self_contained() -> CrtObjects {
+    new(&[
         (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
         (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
         (LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]),
@@ -95,15 +106,15 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects {
     ])
 }
 
-pub(super) fn post_mingw_self_contained() -> CrtObjects {
+pub(super) fn post_i686_mingw_self_contained() -> CrtObjects {
     all("rsend.o")
 }
 
-pub(super) fn pre_mingw() -> CrtObjects {
+pub(super) fn pre_i686_mingw() -> CrtObjects {
     all("rsbegin.o")
 }
 
-pub(super) fn post_mingw() -> CrtObjects {
+pub(super) fn post_i686_mingw() -> CrtObjects {
     all("rsend.o")
 }
 
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
index d227d63c4a3..0ae7cd7a377 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "armebv7r-none-eabi".into(),
         metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian".into()),
-            tier: Some(2),
+            tier: Some(3),
             host_tools: Some(false),
             std: Some(false),
         },
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
index c373afb914e..71ffd8baed5 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "armebv7r-none-eabihf".into(),
         metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian, hardfloat".into()),
-            tier: Some(2),
+            tier: Some(3),
             host_tools: Some(false),
             std: Some(false),
         },
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
index e775c8fc524..a0d403bd05e 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
+use crate::spec::{
+    Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, crt_objects,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -15,6 +17,10 @@ pub(crate) fn target() -> Target {
         &["-m", "i386pe", "--large-address-aware"],
     );
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]);
+    base.pre_link_objects = crt_objects::pre_i686_mingw();
+    base.post_link_objects = crt_objects::post_i686_mingw();
+    base.pre_link_objects_self_contained = crt_objects::pre_i686_mingw_self_contained();
+    base.post_link_objects_self_contained = crt_objects::post_i686_mingw_self_contained();
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),