diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b5a59442f14a4..9cb193b4a6781 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -488,6 +488,7 @@ pub struct Crate {
 /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct MetaItem {
+    pub unsafety: Safety,
     pub path: Path,
     pub kind: MetaItemKind,
     pub span: Span,
@@ -2823,7 +2824,12 @@ pub struct NormalAttr {
 impl NormalAttr {
     pub fn from_ident(ident: Ident) -> Self {
         Self {
-            item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
+            item: AttrItem {
+                unsafety: Safety::Default,
+                path: Path::from_ident(ident),
+                args: AttrArgs::Empty,
+                tokens: None,
+            },
             tokens: None,
         }
     }
@@ -2831,6 +2837,7 @@ impl NormalAttr {
 
 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct AttrItem {
+    pub unsafety: Safety,
     pub path: Path,
     pub args: AttrArgs,
     // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index d5c9fc960c86b..676a2377c3b35 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -1,6 +1,8 @@
 //! Functions dealing with attributes and meta items.
 
-use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
+use crate::ast::{
+    AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety,
+};
 use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
 use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
@@ -238,7 +240,12 @@ impl AttrItem {
     }
 
     pub fn meta(&self, span: Span) -> Option<MetaItem> {
-        Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
+        Some(MetaItem {
+            unsafety: Safety::Default,
+            path: self.path.clone(),
+            kind: self.meta_kind()?,
+            span,
+        })
     }
 
     pub fn meta_kind(&self) -> Option<MetaItemKind> {
@@ -371,7 +378,10 @@ impl MetaItem {
             _ => path.span.hi(),
         };
         let span = path.span.with_hi(hi);
-        Some(MetaItem { path, kind, span })
+        // FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`,
+        // but as a parenthesized list. This (and likely `MetaItem`) should be changed in
+        // such a way that builtin macros don't accept extraneous `unsafe()`.
+        Some(MetaItem { unsafety: Safety::Default, path, kind, span })
     }
 }
 
@@ -555,11 +565,12 @@ pub fn mk_doc_comment(
 pub fn mk_attr(
     g: &AttrIdGenerator,
     style: AttrStyle,
+    unsafety: Safety,
     path: Path,
     args: AttrArgs,
     span: Span,
 ) -> Attribute {
-    mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
+    mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
 }
 
 pub fn mk_attr_from_item(
@@ -577,15 +588,22 @@ pub fn mk_attr_from_item(
     }
 }
 
-pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
+pub fn mk_attr_word(
+    g: &AttrIdGenerator,
+    style: AttrStyle,
+    unsafety: Safety,
+    name: Symbol,
+    span: Span,
+) -> Attribute {
     let path = Path::from_ident(Ident::new(name, span));
     let args = AttrArgs::Empty;
-    mk_attr(g, style, path, args, span)
+    mk_attr(g, style, unsafety, path, args, span)
 }
 
 pub fn mk_attr_nested_word(
     g: &AttrIdGenerator,
     style: AttrStyle,
+    unsafety: Safety,
     outer: Symbol,
     inner: Symbol,
     span: Span,
@@ -601,12 +619,13 @@ pub fn mk_attr_nested_word(
         delim: Delimiter::Parenthesis,
         tokens: inner_tokens,
     });
-    mk_attr(g, style, path, attr_args, span)
+    mk_attr(g, style, unsafety, path, attr_args, span)
 }
 
 pub fn mk_attr_name_value_str(
     g: &AttrIdGenerator,
     style: AttrStyle,
+    unsafety: Safety,
     name: Symbol,
     val: Symbol,
     span: Span,
@@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str(
     });
     let path = Path::from_ident(Ident::new(name, span));
     let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
-    mk_attr(g, style, path, args, span)
+    mk_attr(g, style, unsafety, path, args, span)
 }
 
 pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 635535a1125d8..cc33ce2cb5629 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -647,8 +647,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
     let Attribute { kind, id: _, style: _, span } = attr;
     match kind {
         AttrKind::Normal(normal) => {
-            let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
-                &mut **normal;
+            let NormalAttr {
+                item: AttrItem { unsafety: _, path, args, tokens },
+                tokens: attr_tokens,
+            } = &mut **normal;
             vis.visit_path(path);
             visit_attr_args(args, vis);
             visit_lazy_tts(tokens, vis);
@@ -678,7 +680,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T
 }
 
 fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
-    let MetaItem { path: _, kind, span } = mi;
+    let MetaItem { unsafety: _, path: _, kind, span } = mi;
     match kind {
         MetaItemKind::Word => {}
         MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)),
@@ -840,7 +842,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
         token::NtTy(ty) => vis.visit_ty(ty),
         token::NtLiteral(expr) => vis.visit_expr(expr),
         token::NtMeta(item) => {
-            let AttrItem { path, args, tokens } = item.deref_mut();
+            let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
             vis.visit_path(path);
             visit_attr_args(args, vis);
             visit_lazy_tts(tokens, vis);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a553109092842..77f95869e9dac 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1805,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let attr = attr::mk_attr_nested_word(
             &self.tcx.sess.psess.attr_id_generator,
             AttrStyle::Outer,
+            Safety::Default,
             sym::allow,
             sym::unreachable_code,
             self.lower_span(span),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index cd8afd076bbe8..1c6b5b9af1954 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -905,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let kind = match attr.kind {
             AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
                 item: AttrItem {
+                    unsafety: normal.item.unsafety,
                     path: normal.item.path.clone(),
                     args: self.lower_attr_args(&normal.item.args),
                     tokens: None,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index a9dca9b6a293b..764d942836c20 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -561,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(mut_ref, "mutable by-reference bindings are experimental");
     gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
     gate_all!(global_registration, "global registration is experimental");
+    gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
 
     if !visitor.features.never_patterns {
         if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ca26b436b82ed..f32b63a39f0ac 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
 use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{Comment, CommentStyle};
-use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
+use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety};
 use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
 use rustc_ast::{GenericArg, GenericBound, SelfKind};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
@@ -249,6 +249,7 @@ pub fn print_crate<'a>(
         let fake_attr = attr::mk_attr_nested_word(
             g,
             ast::AttrStyle::Inner,
+            Safety::Default,
             sym::feature,
             sym::prelude_import,
             DUMMY_SP,
@@ -259,7 +260,13 @@ pub fn print_crate<'a>(
         // root, so this is not needed, and actually breaks things.
         if edition.is_rust_2015() {
             // `#![no_std]`
-            let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
+            let fake_attr = attr::mk_attr_word(
+                g,
+                ast::AttrStyle::Inner,
+                Safety::Default,
+                sym::no_std,
+                DUMMY_SP,
+            );
             s.print_attribute(&fake_attr);
         }
     }
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index a3d6a1c736072..2d1269e1b6ad8 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
 builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
     .suggestion = remove the value
 
+builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
+    .suggestion = remove the `unsafe(...)`
+
 builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
     .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
     .custom = use `std::env::var({$var_expr})` to read the variable at run time
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index e9b63b4abebb6..16184ec75113a 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -17,7 +17,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
         ));
 
         let start_span = parser.token.span;
-        let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
+        let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
             Ok(ai) => ai,
             Err(err) => {
                 err.emit();
@@ -33,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
         krate.attrs.push(mk_attr(
             &psess.attr_id_generator,
             AttrStyle::Inner,
+            unsafety,
             path,
             args,
             start_span.to(end_span),
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index d14858e5c1db3..b5cbfdf0ec6e4 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
 use crate::errors;
 
 use rustc_ast as ast;
-use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
 use rustc_expand::base::{
     Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
 };
@@ -60,6 +60,7 @@ impl MultiItemModifier for Expander {
                                 // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
                                 // paths.
                                 report_path_args(sess, meta);
+                                report_unsafe_args(sess, meta);
                                 meta.path.clone()
                             })
                             .map(|path| DeriveResolution {
@@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
         }
     }
 }
+
+fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
+    match meta.unsafety {
+        Safety::Unsafe(span) => {
+            sess.dcx().emit_err(errors::DeriveUnsafePath { span });
+        }
+        Safety::Default => {}
+        Safety::Safe(_) => unreachable!(),
+    }
+}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index d157703723beb..b14eb2b5ee600 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -295,6 +295,13 @@ pub(crate) struct DerivePathArgsValue {
     pub(crate) span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(builtin_macros_derive_unsafe_path)]
+pub(crate) struct DeriveUnsafePath {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(builtin_macros_no_default_variant)]
 #[help]
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 38ac2f15fe757..ba4e5cfd13070 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
                     let allow_dead_code = attr::mk_attr_nested_word(
                         &self.sess.psess.attr_id_generator,
                         ast::AttrStyle::Outer,
+                        ast::Safety::Default,
                         sym::allow,
                         sym::dead_code,
                         self.def_site,
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index b3d41908260ed..37dfd8305126a 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -666,7 +666,7 @@ impl<'a> ExtCtxt<'a> {
     // Builds `#[name]`.
     pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
         let g = &self.sess.psess.attr_id_generator;
-        attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span)
+        attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span)
     }
 
     // Builds `#[name = val]`.
@@ -674,12 +674,26 @@ impl<'a> ExtCtxt<'a> {
     // Note: `span` is used for both the identifier and the value.
     pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
         let g = &self.sess.psess.attr_id_generator;
-        attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
+        attr::mk_attr_name_value_str(
+            g,
+            ast::AttrStyle::Outer,
+            ast::Safety::Default,
+            name,
+            val,
+            span,
+        )
     }
 
     // Builds `#[outer(inner)]`.
     pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute {
         let g = &self.sess.psess.attr_id_generator;
-        attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span)
+        attr::mk_attr_nested_word(
+            g,
+            ast::AttrStyle::Outer,
+            ast::Safety::Default,
+            outer,
+            inner,
+            span,
+        )
     }
 }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index d8f0f221189ad..c28a09eb57c77 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -778,7 +778,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
-                    let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
+                    // The `MetaItem` representing the trait to derive can't
+                    // have an unsafe around it (as of now).
+                    let meta = ast::MetaItem {
+                        unsafety: ast::Safety::Default,
+                        kind: MetaItemKind::Word,
+                        span,
+                        path,
+                    };
                     let items = match expander.expand(self.cx, span, &meta, item, is_const) {
                         ExpandResult::Ready(items) => items,
                         ExpandResult::Retry(item) => {
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 7c76392858cd5..08b2115b79406 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -80,6 +80,8 @@ declare_features! (
     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
     /// Allows `c"foo"` literals.
     (accepted, c_str_literals, "1.77.0", Some(105723)),
+    /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries and treat `extern "C" fn` as nounwind.
+    (accepted, c_unwind, "CURRENT_RUSTC_VERSION", Some(74990)),
     /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
     (accepted, cfg_attr_multi, "1.33.0", Some(54881)),
     /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 8b7e93fd55587..9b5e4e50d3ca8 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -59,6 +59,16 @@ pub enum AttributeType {
     CrateLevel,
 }
 
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum AttributeSafety {
+    /// Normal attribute that does not need `#[unsafe(...)]`
+    Normal,
+
+    /// Unsafe attribute that requires safety obligations
+    /// to be discharged
+    Unsafe,
+}
+
 #[derive(Clone, Copy)]
 pub enum AttributeGate {
     /// Is gated by a given feature gate, reason
@@ -172,11 +182,23 @@ macro_rules! template {
 }
 
 macro_rules! ungated {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
+            safety: AttributeSafety::Unsafe,
+            template: $tpl,
+            gate: Ungated,
+            duplicates: $duplicates,
+        }
+    };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
+            safety: AttributeSafety::Normal,
             template: $tpl,
             gate: Ungated,
             duplicates: $duplicates,
@@ -185,11 +207,34 @@ macro_rules! ungated {
 }
 
 macro_rules! gated {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
+            safety: AttributeSafety::Unsafe,
+            template: $tpl,
+            duplicates: $duplicates,
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+        }
+    };
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
+            safety: AttributeSafety::Unsafe,
+            template: $tpl,
+            duplicates: $duplicates,
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+        }
+    };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
+            safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
@@ -200,6 +245,7 @@ macro_rules! gated {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
+            safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
@@ -228,6 +274,7 @@ macro_rules! rustc_attr {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
+            safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
@@ -258,6 +305,7 @@ pub struct BuiltinAttribute {
     /// Otherwise, it can only be used in the local crate.
     pub encode_cross_crate: EncodeCrossCrate,
     pub type_: AttributeType,
+    pub safety: AttributeSafety,
     pub template: AttributeTemplate,
     pub duplicates: AttributeDuplicates,
     pub gate: AttributeGate,
@@ -375,9 +423,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
-    ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
+    ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+    ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+    ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
     ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
 
@@ -486,11 +534,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     gated!(
-        ffi_pure, Normal, template!(Word), WarnFollowing,
+        unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(ffi_pure)
     ),
     gated!(
-        ffi_const, Normal, template!(Word), WarnFollowing,
+        unsafe ffi_const, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(ffi_const)
     ),
     gated!(
@@ -850,6 +898,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
         encode_cross_crate: EncodeCrossCrate::Yes,
         type_: Normal,
+        safety: AttributeSafety::Normal,
         template: template!(NameValueStr: "name"),
         duplicates: ErrorFollowing,
         gate: Gated(
@@ -1096,6 +1145,10 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool {
     })
 }
 
+pub fn is_unsafe_attr(name: Symbol) -> bool {
+    BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe)
+}
+
 pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
     LazyLock::new(|| {
         let mut map = FxHashMap::default();
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 9cbf836ec76f0..9db9073e2f02f 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -123,8 +123,8 @@ pub use accepted::ACCEPTED_FEATURES;
 pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
-    is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
-    GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
+    BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::REMOVED_FEATURES;
 pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 8add2b9276142..1ad41f5278fb5 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -363,8 +363,6 @@ declare_features! (
     (unstable, async_for_loop, "1.77.0", Some(118898)),
     /// Allows builtin # foo() syntax
     (unstable, builtin_syntax, "1.71.0", Some(110680)),
-    /// Treat `extern "C"` function as nounwind.
-    (unstable, c_unwind, "1.52.0", Some(74990)),
     /// Allows using C-variadics.
     (unstable, c_variadic, "1.34.0", Some(44930)),
     /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
@@ -620,6 +618,8 @@ declare_features! (
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
     /// Allows unnamed fields of struct and union type
     (incomplete, unnamed_fields, "1.74.0", Some(49804)),
+    /// Allows unsafe attributes.
+    (unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)),
     /// Allows unsafe on extern declarations and safety qualifiers over internal items.
     (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
     /// Allows unsized fn parameters.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 142872009bf21..596f423fc92bf 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1181,37 +1181,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
     // ABIs have such an option. Otherwise the only other thing here is Rust
     // itself, and those ABIs are determined by the panic strategy configured
     // for this compilation.
-    //
-    // Unfortunately at this time there's also another caveat. Rust [RFC
-    // 2945][rfc] has been accepted and is in the process of being implemented
-    // and stabilized. In this interim state we need to deal with historical
-    // rustc behavior as well as plan for future rustc behavior.
-    //
-    // Historically functions declared with `extern "C"` were marked at the
-    // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
-    // or not. This is UB for functions in `panic=unwind` mode that then
-    // actually panic and unwind. Note that this behavior is true for both
-    // externally declared functions as well as Rust-defined function.
-    //
-    // To fix this UB rustc would like to change in the future to catch unwinds
-    // from function calls that may unwind within a Rust-defined `extern "C"`
-    // function and forcibly abort the process, thereby respecting the
-    // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
-    // ready to roll out, so determining whether or not the `C` family of ABIs
-    // unwinds is conditional not only on their definition but also whether the
-    // `#![feature(c_unwind)]` feature gate is active.
-    //
-    // Note that this means that unlike historical compilers rustc now, by
-    // default, unconditionally thinks that the `C` ABI may unwind. This will
-    // prevent some optimization opportunities, however, so we try to scope this
-    // change and only assume that `C` unwinds with `panic=unwind` (as opposed
-    // to `panic=abort`).
-    //
-    // Eventually the check against `c_unwind` here will ideally get removed and
-    // this'll be a little cleaner as it'll be a straightforward check of the
-    // ABI.
-    //
-    // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
     use SpecAbi::*;
     match abi {
         C { unwind }
@@ -1223,10 +1192,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
         | Thiscall { unwind }
         | Aapcs { unwind }
         | Win64 { unwind }
-        | SysV64 { unwind } => {
-            unwind
-                || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
-        }
+        | SysV64 { unwind } => unwind,
         PtxKernel
         | Msp430Interrupt
         | X86Interrupt
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 5e3cd85367508..0cb304da80a10 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -11,38 +11,6 @@ use rustc_target::spec::PanicStrategy;
 
 use crate::errors;
 
-/// Some of the functions declared as "may unwind" by `fn_can_unwind` can't actually unwind. In
-/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to consider
-/// it cannot-unwind here. So below we check `fn_can_unwind() && abi_can_unwind()` before concluding
-/// that a function call can unwind.
-fn abi_can_unwind(abi: Abi) -> bool {
-    use Abi::*;
-    match abi {
-        C { unwind }
-        | System { unwind }
-        | Cdecl { unwind }
-        | Stdcall { unwind }
-        | Fastcall { unwind }
-        | Vectorcall { unwind }
-        | Thiscall { unwind }
-        | Aapcs { unwind }
-        | Win64 { unwind }
-        | SysV64 { unwind } => unwind,
-        PtxKernel
-        | Msp430Interrupt
-        | X86Interrupt
-        | EfiApi
-        | AvrInterrupt
-        | AvrNonBlockingInterrupt
-        | RiscvInterruptM
-        | RiscvInterruptS
-        | CCmseNonSecureCall
-        | Wasm
-        | Unadjusted => false,
-        RustIntrinsic | Rust | RustCall | RustCold => unreachable!(), // these ABIs are already skipped earlier
-    }
-}
-
 // Check if the body of this def_id can possibly leak a foreign unwind into Rust code.
 fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     debug!("has_ffi_unwind_calls({local_def_id:?})");
@@ -103,7 +71,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
             _ => bug!("invalid callee of type {:?}", ty),
         };
 
-        if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) {
+        if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) {
             // We have detected a call that can possibly leak foreign unwind.
             //
             // Because the function body itself can unwind, we are not aborting this function call
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 4acc610d8c405..58fef9b6c4562 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -7,7 +7,7 @@ use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Delimiter};
 use rustc_errors::{codes::*, Diag, PResult};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, Span};
 use thin_vec::ThinVec;
 use tracing::debug;
 
@@ -252,9 +252,23 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtMeta, |attr| attr.into_inner());
 
         let do_parse = |this: &mut Self| {
+            let is_unsafe = this.eat_keyword(kw::Unsafe);
+            let unsafety = if is_unsafe {
+                let unsafe_span = this.prev_token.span;
+                this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
+                this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
+
+                ast::Safety::Unsafe(unsafe_span)
+            } else {
+                ast::Safety::Default
+            };
+
             let path = this.parse_path(PathStyle::Mod)?;
             let args = this.parse_attr_args()?;
-            Ok(ast::AttrItem { path, args, tokens: None })
+            if is_unsafe {
+                this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
+            }
+            Ok(ast::AttrItem { unsafety, path, args, tokens: None })
         };
         // Attr items don't have attributes
         if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
@@ -375,10 +389,25 @@ impl<'a> Parser<'a> {
         }
 
         let lo = self.token.span;
+        let is_unsafe = self.eat_keyword(kw::Unsafe);
+        let unsafety = if is_unsafe {
+            let unsafe_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
+            self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
+
+            ast::Safety::Unsafe(unsafe_span)
+        } else {
+            ast::Safety::Default
+        };
+
         let path = self.parse_path(PathStyle::Mod)?;
         let kind = self.parse_meta_item_kind()?;
+        if is_unsafe {
+            self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
+        }
         let span = lo.to(self.prev_token.span);
-        Ok(ast::MetaItem { path, kind, span })
+
+        Ok(ast::MetaItem { unsafety, path, kind, span })
     }
 
     pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index b91ef1ae1f320..58342ff829071 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -42,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
 pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
     let item = attr.get_normal_item();
     Ok(MetaItem {
+        unsafety: item.unsafety,
         span: attr.span,
         path: item.path.clone(),
         kind: match &item.args {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d850644bb452f..07c82065a80d1 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level =
 passes_invalid_attr_at_crate_level_item =
     the inner attribute doesn't annotate this {$kind}
 
+passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
+    .suggestion = remove the `unsafe(...)`
+    .note = extraneous unsafe is not allowed in attributes
+
 passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
 
 passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 39cb48c1af3aa..6ce7c41acc8ff 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,9 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::StashKey;
 use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan};
-use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{
+    is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP,
+};
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir};
@@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
+            self.check_unsafe_attr(attr);
+
             match attr.path().as_slice() {
                 [sym::diagnostic, sym::do_not_recommend] => {
                     self.check_do_not_recommend(attr.span, hir_id, target)
@@ -308,6 +312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         true
     }
 
+    /// Checks if `unsafe()` is applied to an invalid attribute.
+    fn check_unsafe_attr(&self, attr: &Attribute) {
+        if !attr.is_doc_comment() {
+            let attr_item = attr.get_normal_item();
+            if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety {
+                if !is_unsafe_attr(attr.name_or_empty()) {
+                    self.dcx().emit_err(errors::InvalidAttrUnsafe {
+                        span: unsafe_span,
+                        name: attr_item.path.clone(),
+                    });
+                }
+            }
+        }
+    }
+
     /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
     fn check_diagnostic_on_unimplemented(
         &self,
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ddc50e2b811a2..2cb3c5d8965c8 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::builtin::DEAD_CODE;
@@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     )
 }
 
-fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
+struct Publicness {
+    ty_is_public: bool,
+    ty_and_all_fields_are_public: bool,
+}
+
+impl Publicness {
+    fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
+        Self { ty_is_public, ty_and_all_fields_are_public }
+    }
+}
+
+fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
+    // treat PhantomData and positional ZST as public,
+    // we don't want to lint types which only have them,
+    // cause it's a common way to use such types to check things like well-formedness
+    tcx.adt_def(id).all_fields().all(|field| {
+        let field_type = tcx.type_of(field.did).instantiate_identity();
+        if field_type.is_phantom_data() {
+            return true;
+        }
+        let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
+        if is_positional
+            && tcx
+                .layout_of(tcx.param_env(field.did).and(field_type))
+                .map_or(true, |layout| layout.is_zst())
+        {
+            return true;
+        }
+        field.vis.is_public()
+    })
+}
+
+/// check struct and its fields are public or not,
+/// for enum and union, just check they are public,
+/// and doesn't solve types like &T for now, just skip them
+fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
     if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
         && let Res::Def(def_kind, def_id) = path.res
         && def_id.is_local()
-        && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
     {
-        tcx.visibility(def_id).is_public()
-    } else {
-        true
+        return match def_kind {
+            DefKind::Enum | DefKind::Union => {
+                let ty_is_public = tcx.visibility(def_id).is_public();
+                Publicness::new(ty_is_public, ty_is_public)
+            }
+            DefKind::Struct => {
+                let ty_is_public = tcx.visibility(def_id).is_public();
+                Publicness::new(
+                    ty_is_public,
+                    ty_is_public && struct_all_fields_are_public(tcx, def_id),
+                )
+            }
+            _ => Publicness::new(true, true),
+        };
     }
+
+    Publicness::new(true, true)
 }
 
 /// Determine if a work from the worklist is coming from the a `#[allow]`
@@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                         {
                             if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
                                 && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
+                                    .ty_and_all_fields_are_public
                             {
-                                // skip methods of private ty,
-                                // they would be solved in `solve_rest_impl_items`
+                                // skip impl-items of non pure pub ty,
+                                // cause we don't know the ty is constructed or not,
+                                // check these later in `solve_rest_impl_items`
                                 continue;
                             }
 
@@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             && let Some(local_def_id) = def_id.as_local()
             && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
         {
-            if self.tcx.visibility(impl_item_id).is_public() {
-                // for the public method, we don't know the trait item is used or not,
-                // so we mark the method live if the self is used
-                return self.live_symbols.contains(&local_def_id);
-            }
-
             if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
                 && let Some(local_id) = trait_item_id.as_local()
             {
-                // for the private method, we can know the trait item is used or not,
+                // for the local impl item, we can know the trait item is used or not,
                 // so we mark the method live if the self is used and the trait item is used
-                return self.live_symbols.contains(&local_id)
-                    && self.live_symbols.contains(&local_def_id);
+                self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
+            } else {
+                // for the foreign method and inherent pub method,
+                // we don't know the trait item or the method is used or not,
+                // so we mark the method live if the self is used
+                self.live_symbols.contains(&local_def_id)
             }
+        } else {
+            false
         }
-        false
     }
 }
 
@@ -747,7 +795,9 @@ fn check_item<'tcx>(
                 .iter()
                 .filter_map(|def_id| def_id.as_local());
 
-            let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
+            let self_ty = tcx.hir().item(id).expect_impl().self_ty;
+            let Publicness { ty_is_public, ty_and_all_fields_are_public } =
+                ty_ref_to_pub_struct(tcx, self_ty);
 
             // And we access the Map here to get HirId from LocalDefId
             for local_def_id in local_def_ids {
@@ -763,18 +813,20 @@ fn check_item<'tcx>(
                 // for trait impl blocks,
                 // mark the method live if the self_ty is public,
                 // or the method is public and may construct self
-                if of_trait
-                    && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
-                        || tcx.visibility(local_def_id).is_public()
-                            && (ty_is_pub || may_construct_self))
+                if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy)
+                    || tcx.visibility(local_def_id).is_public()
+                        && (ty_and_all_fields_are_public || may_construct_self)
                 {
+                    // if the impl item is public,
+                    // and the ty may be constructed or can be constructed in foreign crates,
+                    // mark the impl item live
                     worklist.push((local_def_id, ComesFromAllowExpect::No));
                 } else if let Some(comes_from_allow) =
                     has_allow_dead_code_or_lang_attr(tcx, local_def_id)
                 {
                     worklist.push((local_def_id, comes_from_allow));
-                } else if of_trait {
-                    // private method || public method not constructs self
+                } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
+                    // private impl items of traits || public impl items not constructs self
                     unsolved_impl_items.push((id, local_def_id));
                 }
             }
@@ -841,6 +893,14 @@ fn create_and_seed_worklist(
             effective_vis
                 .is_public_at_level(Level::Reachable)
                 .then_some(id)
+                .filter(|&id|
+                    // checks impls, impl-items and pub structs with all public fields later
+                    match tcx.def_kind(id) {
+                        DefKind::Impl { .. } => false,
+                        DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
+                        DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()),
+                        _ => true
+                    })
                 .map(|id| (id, ComesFromAllowExpect::No))
         })
         // Seed entry point
@@ -1113,10 +1173,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
             || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
         {
             for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
-                // We have diagnosed unused methods in traits
+                // We have diagnosed unused assoc consts and fns in traits
                 if matches!(def_kind, DefKind::Impl { of_trait: true })
-                    && tcx.def_kind(def_id) == DefKind::AssocFn
-                    || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
+                    && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn)
+                    // skip unused public inherent methods,
+                    // cause we have diagnosed unconstructed struct
+                    || matches!(def_kind, DefKind::Impl { of_trait: false })
+                        && tcx.visibility(def_id).is_public()
+                        && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
+                    || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy
                 {
                     continue;
                 }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7fdd9924b513e..a935f1ad7d351 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -4,7 +4,7 @@ use std::{
 };
 
 use crate::fluent_generated as fluent;
-use rustc_ast::Label;
+use rustc_ast::{ast, Label};
 use rustc_errors::{
     codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
@@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel {
     pub item: Option<ItemFollowingInnerAttr>,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_invalid_attr_unsafe)]
+#[note]
+pub struct InvalidAttrUnsafe {
+    #[primary_span]
+    pub span: Span,
+    pub name: ast::Path,
+}
+
 #[derive(Clone, Copy)]
 pub struct ItemFollowingInnerAttr {
     pub span: Span,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f530d1dd1d4bc..935942641677a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1962,6 +1962,7 @@ symbols! {
         unreachable_display,
         unreachable_macro,
         unrestricted_attribute_tokens,
+        unsafe_attributes,
         unsafe_block_in_unsafe_fn,
         unsafe_cell,
         unsafe_cell_raw_get,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 521e4ef0c9edf..381da6f7e2a7a 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -23,7 +23,6 @@
 #![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![feature(option_take_if)]
 #![feature(never_type)]
 #![feature(type_alias_impl_trait)]
 #![recursion_limit = "512"] // For rustdoc
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 0b04fb4a27444..a391141827efe 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -1216,7 +1216,6 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(binary_heap_as_slice)]
     /// use std::collections::BinaryHeap;
     /// use std::io::{self, Write};
     ///
@@ -1225,7 +1224,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
     /// io::sink().write(heap.as_slice()).unwrap();
     /// ```
     #[must_use]
-    #[unstable(feature = "binary_heap_as_slice", issue = "83659")]
+    #[stable(feature = "binary_heap_as_slice", since = "CURRENT_RUSTC_VERSION")]
     pub fn as_slice(&self) -> &[T] {
         self.data.as_slice()
     }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 4ac0c9b15be7a..ab18814bb8176 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -166,13 +166,13 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(c_unwind))]
 #![cfg_attr(bootstrap, feature(exclusive_range_pattern))]
 #![cfg_attr(not(test), feature(coroutine_trait))]
 #![cfg_attr(test, feature(panic_update_hook))]
 #![cfg_attr(test, feature(test))]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
-#![feature(c_unwind)]
 #![feature(cfg_sanitize)]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 8451be63c2b9b..89538f272f069 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -24,7 +24,6 @@
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(binary_heap_drain_sorted)]
 #![feature(slice_ptr_get)]
-#![feature(binary_heap_as_slice)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 89642d6226a24..bd467437281c1 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -199,13 +199,13 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(c_unwind))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
 #![feature(asm_const)]
 #![feature(auto_traits)]
-#![feature(c_unwind)]
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9a527073602e6..e253cfd2822be 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1708,8 +1708,6 @@ impl<T> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(option_take_if)]
-    ///
     /// let mut x = Some(42);
     ///
     /// let prev = x.take_if(|v| if *v == 42 {
@@ -1726,7 +1724,7 @@ impl<T> Option<T> {
     /// assert_eq!(prev, Some(43));
     /// ```
     #[inline]
-    #[unstable(feature = "option_take_if", issue = "98934")]
+    #[stable(feature = "option_take_if", since = "CURRENT_RUSTC_VERSION")]
     pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
     where
         P: FnOnce(&mut T) -> bool,
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index 353de8c5c5743..14ba4af2bb575 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -14,7 +14,7 @@
 #![feature(std_internals)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
-#![feature(c_unwind)]
+#![cfg_attr(bootstrap, feature(c_unwind))]
 #![allow(internal_features)]
 
 #[cfg(target_os = "android")]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index b0245de501e7e..4dc3612060848 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -24,7 +24,7 @@
 #![feature(rustc_attrs)]
 #![panic_runtime]
 #![feature(panic_runtime)]
-#![feature(c_unwind)]
+#![cfg_attr(bootstrap, feature(c_unwind))]
 // `real_imp` is unused with Miri, so silence warnings.
 #![cfg_attr(miri, allow(dead_code))]
 #![allow(internal_features)]
diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs
index 48030f8d82dca..149767bf70521 100644
--- a/library/proc_macro/src/bridge/buffer.rs
+++ b/library/proc_macro/src/bridge/buffer.rs
@@ -119,7 +119,9 @@ impl Write for Buffer {
 }
 
 impl Drop for Buffer {
-    #[inline]
+    // HACK(nbdd0121): Hack to prevent LLVM < 17.0.4 from misoptimising,
+    // change to `#[inline]` if fixed.
+    #[inline(never)]
     fn drop(&mut self) {
         let b = self.take();
         (b.drop)(b);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 9d6576fa84117..ae444836efa48 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -273,12 +273,12 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(c_unwind))]
 #![feature(alloc_error_handler)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
 #![feature(asm_experimental_arch)]
-#![feature(c_unwind)]
 #![feature(cfg_sanitizer_cfi)]
 #![feature(cfg_target_thread_local)]
 #![feature(cfi_encoding)]
diff --git a/library/std/src/sys/pal/windows/c/README.md b/library/std/src/sys/pal/windows/c/README.md
index d458e55efbcdd..efefc5faba7a4 100644
--- a/library/std/src/sys/pal/windows/c/README.md
+++ b/library/std/src/sys/pal/windows/c/README.md
@@ -3,7 +3,7 @@ be edited manually.
 
 To add bindings, edit `bindings.txt` then regenerate using the following command:
 
-    ./x run generate-windows-sys && ./x fmt library/std
+    ./x run generate-windows-sys && ./x fmt
 
 If you need to override generated functions or types then add them to
 `library/std/src/sys/pal/windows/c.rs`.
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 544d9fbf1ae0f..45a1c334a44dd 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -2,7 +2,7 @@
 #![unstable(feature = "panic_unwind", issue = "32837")]
 #![feature(link_cfg)]
 #![feature(staged_api)]
-#![feature(c_unwind)]
+#![cfg_attr(bootstrap, feature(c_unwind))]
 #![feature(strict_provenance)]
 #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1b55fc85da429..9df4698f21f3a 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -9,7 +9,6 @@ use crate::core::builder;
 use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
-use crate::utils::exec::BootstrapCommand;
 use crate::utils::helpers::output;
 use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::Compiler;
@@ -110,9 +109,8 @@ impl Step for ToolBuild {
             &self.target,
         );
 
-        let mut cargo = Command::from(cargo);
         // we check this below
-        let build_success = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure());
+        let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {});
 
         builder.save_toolstate(
             tool,
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 3e1ac2fa8ad7b..72ab8ab5ce9b5 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -213,21 +213,39 @@ The valid emit kinds are:
   `CRATE_NAME.o`.
 
 The output filename can be set with the [`-o` flag](#option-o-output). A
-suffix may be added to the filename with the [`-C extra-filename`
-flag](codegen-options/index.md#extra-filename). The files are written to the
-current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each
-emission type may also specify the output filename with the form `KIND=PATH`,
-which takes precedence over the `-o` flag.
-Specifying `-o -` or `--emit KIND=-` asks rustc to emit to stdout.
-Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to
-stdout despite it being a tty or not. This will result in an error if any
-binary output type is written to stdout that is a tty.
-This will also result in an error if multiple output types
-would be written to stdout, because they would be all mixed together.
+suffix may be added to the filename with the
+[`-C extra-filename` flag](codegen-options/index.md#extra-filename).
+
+Output files are written to the current directory unless the
+[`--out-dir` flag](#option-out-dir) is used.
 
 [LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
 [LLVM IR]: https://llvm.org/docs/LangRef.html
 
+### Custom paths for individual emit kinds
+
+Each emit type can optionally be followed by `=` to specify an explicit output
+path that only applies to the output of that type. For example:
+
+- `--emit=link,dep-info=/path/to/dep-info.d`
+  - Emit the crate itself as normal,
+    and also emit dependency info to the specified path.
+- `--emit=llvm-ir=-,mir`
+  - Emit MIR to the default filename (based on crate name),
+    and emit LLVM IR to stdout.
+
+### Emitting to stdout
+
+When using `--emit` or [`-o`](#option-o-output), output can be sent to stdout
+by specifying `-` as the path (e.g. `-o -`).
+
+Binary output types can only be written to stdout if it is not a tty.
+Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to
+stdout regardless of whether it is a tty or not.
+
+Only one type of output can be written to stdout. Attempting to write multiple
+types to stdout at the same time will result in an error.
+
 <a id="option-print"></a>
 ## `--print`: print compiler information
 
diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md
deleted file mode 100644
index fb32918d5e439..0000000000000
--- a/src/doc/unstable-book/src/language-features/c-unwind.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# `c_unwind`
-
-The tracking issue for this feature is: [#74990]
-
-[#74990]: https://github.com/rust-lang/rust/issues/74990
-
-------------------------
-
-Introduces new ABI strings:
-- "C-unwind"
-- "cdecl-unwind"
-- "stdcall-unwind"
-- "fastcall-unwind"
-- "vectorcall-unwind"
-- "thiscall-unwind"
-- "aapcs-unwind"
-- "win64-unwind"
-- "sysv64-unwind"
-- "system-unwind"
-
-These enable unwinding from other languages (such as C++) into Rust frames and
-from Rust into other languages.
-
-See [RFC 2945] for more information.
-
-[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 20bcf1abf417b..2857f74c744f5 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -1,6 +1,6 @@
 use super::*;
 
-use rustc_ast::{MetaItemLit, Path, StrStyle};
+use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
 use rustc_span::create_default_session_globals_then;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::DUMMY_SP;
@@ -16,6 +16,7 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
 
 fn dummy_meta_item_word(name: &str) -> MetaItem {
     MetaItem {
+        unsafety: Safety::Default,
         path: Path::from_ident(Ident::from_str(name)),
         kind: MetaItemKind::Word,
         span: DUMMY_SP,
@@ -25,6 +26,7 @@ fn dummy_meta_item_word(name: &str) -> MetaItem {
 fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
     let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
     MetaItem {
+        unsafety: Safety::Default,
         path: Path::from_ident(Ident::from_str(name)),
         kind: MetaItemKind::NameValue(lit),
         span: DUMMY_SP,
@@ -34,6 +36,7 @@ fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> Meta
 macro_rules! dummy_meta_item_list {
     ($name:ident, [$($list:ident),* $(,)?]) => {
         MetaItem {
+            unsafety: Safety::Default,
             path: Path::from_ident(Ident::from_str(stringify!($name))),
             kind: MetaItemKind::List(thin_vec![
                 $(
@@ -48,6 +51,7 @@ macro_rules! dummy_meta_item_list {
 
     ($name:ident, [$($list:expr),* $(,)?]) => {
         MetaItem {
+            unsafety: Safety::Default,
             path: Path::from_ident(Ident::from_str(stringify!($name))),
             kind: MetaItemKind::List(thin_vec![
                 $(
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 2c425a07b2acd..41972b6994c60 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3515,7 +3515,6 @@ impl<'test> TestCx<'test> {
             .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", &rmake_out_dir)
@@ -3567,7 +3566,7 @@ impl<'test> TestCx<'test> {
             .env(dylib_env_var(), &dylib_env_paths)
             .env("TARGET", &self.config.target)
             .env("PYTHON", &self.config.python)
-            .env("S", &src_root)
+            .env("SOURCE_ROOT", &src_root)
             .env("RUST_BUILD_STAGE", &self.config.stage_id)
             .env("RUSTC", cwd.join(&self.config.rustc_path))
             .env("TMPDIR", &rmake_out_dir)
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
index 6d68b9a46d9e3..dc192d0319636 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
@@ -1,5 +1,3 @@
-#![feature(c_unwind)]
-
 #[no_mangle]
 extern "C-unwind" fn unwind() {
     panic!();
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
index e6aff19b02d49..1382e9571f316 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
@@ -4,7 +4,7 @@
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
 //@[definition,both]error-in-other-file: aborted execution
-#![feature(rustc_attrs, c_unwind)]
+#![feature(rustc_attrs)]
 
 #[cfg_attr(any(definition, both), rustc_nounwind)]
 #[no_mangle]
diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.rs b/src/tools/miri/tests/fail/panic/bad_unwind.rs
index 8c8a9f18cdc63..5370485b2a623 100644
--- a/src/tools/miri/tests/fail/panic/bad_unwind.rs
+++ b/src/tools/miri/tests/fail/panic/bad_unwind.rs
@@ -1,5 +1,3 @@
-#![feature(c_unwind)]
-
 //! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
 // The opposite version (callee does not allow unwinding) is impossible to
 // even write: MIR validation catches functions that have `UnwindContinue` but
diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs
index 7c6728280305d..465625c757251 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.rs
+++ b/src/tools/miri/tests/fail/terminate-terminator.rs
@@ -7,8 +7,6 @@
 // Enable MIR inlining to ensure that `TerminatorKind::UnwindTerminate` is generated
 // instead of just `UnwindAction::Terminate`.
 
-#![feature(c_unwind)]
-
 struct Foo;
 
 impl Drop for Foo {
diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs
index 86406872c5991..465e07c8db4b8 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.rs
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs
@@ -3,8 +3,6 @@
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
-#![feature(c_unwind)]
-
 extern "C" fn panic_abort() {
     panic!()
 }
diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
index 71b799a1f12ba..0e8d45af27fdf 100644
--- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
+++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
@@ -2,7 +2,7 @@
 // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function
 // `__rust_start_panic`).
 // no-prefer-dynamic
-#![feature(c_unwind, unboxed_closures)]
+#![feature(unboxed_closures)]
 
 use std::panic;
 
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index d74a0272a627e..0f9d5a3b6c365 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -89,7 +89,7 @@ pub fn htmldocck() -> Command {
 
 /// Path to the root rust-lang/rust source checkout.
 pub fn source_root() -> PathBuf {
-    env_var("S").into()
+    env_var("SOURCE_ROOT").into()
 }
 
 /// Construct the static library name based on the platform.
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 4e840dbfbb441..40c7c597e9b48 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -214,22 +214,16 @@ impl Write for CombinedEncoder {
     }
 
     fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
-        self.encoders
-            .par_iter_mut()
-            .map(|w| w.write_all(buf))
-            .collect::<std::io::Result<Vec<()>>>()?;
-        Ok(())
+        self.encoders.par_iter_mut().try_for_each(|w| w.write_all(buf))
     }
 
     fn flush(&mut self) -> std::io::Result<()> {
-        self.encoders.par_iter_mut().map(|w| w.flush()).collect::<std::io::Result<Vec<()>>>()?;
-        Ok(())
+        self.encoders.par_iter_mut().try_for_each(Write::flush)
     }
 }
 
 impl Encoder for CombinedEncoder {
     fn finish(self: Box<Self>) -> Result<(), Error> {
-        self.encoders.into_par_iter().map(|e| e.finish()).collect::<Result<Vec<()>, Error>>()?;
-        Ok(())
+        self.encoders.into_par_iter().try_for_each(Encoder::finish)
     }
 }
diff --git a/tests/assembly/asm/aarch64-modifiers.rs b/tests/assembly/asm/aarch64-modifiers.rs
index ffba06ae47bb4..b7ef1d77ea023 100644
--- a/tests/assembly/asm/aarch64-modifiers.rs
+++ b/tests/assembly/asm/aarch64-modifiers.rs
@@ -1,5 +1,5 @@
 //@ assembly-output: emit-asm
-//@ compile-flags: -O
+//@ compile-flags: -O -C panic=abort
 //@ compile-flags: --target aarch64-unknown-linux-gnu
 //@ needs-llvm-components: aarch64
 
diff --git a/tests/assembly/asm/arm-modifiers.rs b/tests/assembly/asm/arm-modifiers.rs
index fa2e75eb35b04..0674e169d72e6 100644
--- a/tests/assembly/asm/arm-modifiers.rs
+++ b/tests/assembly/asm/arm-modifiers.rs
@@ -1,5 +1,5 @@
 //@ assembly-output: emit-asm
-//@ compile-flags: -O
+//@ compile-flags: -O -C panic=abort
 //@ compile-flags: --target armv7-unknown-linux-gnueabihf
 //@ compile-flags: -C target-feature=+neon
 //@ needs-llvm-components: arm
diff --git a/tests/assembly/asm/x86-modifiers.rs b/tests/assembly/asm/x86-modifiers.rs
index 1a92585298d94..c5e393b10564e 100644
--- a/tests/assembly/asm/x86-modifiers.rs
+++ b/tests/assembly/asm/x86-modifiers.rs
@@ -1,6 +1,6 @@
 //@ revisions: x86_64 i686
 //@ assembly-output: emit-asm
-//@ compile-flags: -O
+//@ compile-flags: -O -C panic=abort
 //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
 //@[x86_64] needs-llvm-components: x86
 //@[i686] compile-flags: --target i686-unknown-linux-gnu
diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs
index 8264a70685207..cd22ca067061f 100644
--- a/tests/assembly/simd-bitmask.rs
+++ b/tests/assembly/simd-bitmask.rs
@@ -11,7 +11,7 @@
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [aarch64] min-llvm-version: 18.0
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-gather.rs b/tests/assembly/simd-intrinsic-gather.rs
index ef6b597c25f1e..83015f05ab3ee 100644
--- a/tests/assembly/simd-intrinsic-gather.rs
+++ b/tests/assembly/simd-intrinsic-gather.rs
@@ -4,7 +4,7 @@
 //@ [x86-avx512] needs-llvm-components: x86
 //@ [x86-avx512] min-llvm-version: 18.0
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-mask-load.rs b/tests/assembly/simd-intrinsic-mask-load.rs
index 49d231c45f858..d537c143d365b 100644
--- a/tests/assembly/simd-intrinsic-mask-load.rs
+++ b/tests/assembly/simd-intrinsic-mask-load.rs
@@ -6,7 +6,7 @@
 //@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
 //@ [x86-avx512] needs-llvm-components: x86
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-mask-reduce.rs b/tests/assembly/simd-intrinsic-mask-reduce.rs
index 72c3f6376e807..dd4dbaeda76c0 100644
--- a/tests/assembly/simd-intrinsic-mask-reduce.rs
+++ b/tests/assembly/simd-intrinsic-mask-reduce.rs
@@ -8,7 +8,7 @@
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [aarch64] min-llvm-version: 18.0
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-mask-store.rs b/tests/assembly/simd-intrinsic-mask-store.rs
index a6611e1c23d5c..5d4c00c382337 100644
--- a/tests/assembly/simd-intrinsic-mask-store.rs
+++ b/tests/assembly/simd-intrinsic-mask-store.rs
@@ -6,7 +6,7 @@
 //@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
 //@ [x86-avx512] needs-llvm-components: x86
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-scatter.rs b/tests/assembly/simd-intrinsic-scatter.rs
index 6ffefb0801aec..55095e4cb681f 100644
--- a/tests/assembly/simd-intrinsic-scatter.rs
+++ b/tests/assembly/simd-intrinsic-scatter.rs
@@ -4,7 +4,7 @@
 //@ [x86-avx512] needs-llvm-components: x86
 //@ [x86-avx512] min-llvm-version: 18.0
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs
index 3f36402e3d0d5..4dfc2f9ed1fb2 100644
--- a/tests/assembly/simd-intrinsic-select.rs
+++ b/tests/assembly/simd-intrinsic-select.rs
@@ -9,7 +9,7 @@
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [aarch64] min-llvm-version: 18.0
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O
+//@ compile-flags: --crate-type=lib -O -C panic=abort
 
 #![feature(no_core, lang_items, repr_simd, intrinsics)]
 #![no_core]
diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs
index 23d09e0d8af3e..b4cd99272b152 100644
--- a/tests/codegen-units/item-collection/generic-impl.rs
+++ b/tests/codegen-units/item-collection/generic-impl.rs
@@ -22,16 +22,16 @@ impl<T> Struct<T> {
     }
 }
 
-pub struct LifeTimeOnly<'a> {
+pub struct _LifeTimeOnly<'a> {
     _a: &'a u32,
 }
 
-impl<'a> LifeTimeOnly<'a> {
-    //~ MONO_ITEM fn LifeTimeOnly::<'_>::foo
+impl<'a> _LifeTimeOnly<'a> {
+    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo
     pub fn foo(&self) {}
-    //~ MONO_ITEM fn LifeTimeOnly::<'_>::bar
+    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar
     pub fn bar(&'a self) {}
-    //~ MONO_ITEM fn LifeTimeOnly::<'_>::baz
+    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz
     pub fn baz<'b>(&'b self) {}
 
     pub fn non_instantiated<T>(&self) {}
diff --git a/tests/codegen-units/item-collection/overloaded-operators.rs b/tests/codegen-units/item-collection/overloaded-operators.rs
index 69b55695d3d30..e00e22dbab996 100644
--- a/tests/codegen-units/item-collection/overloaded-operators.rs
+++ b/tests/codegen-units/item-collection/overloaded-operators.rs
@@ -5,44 +5,44 @@
 
 use std::ops::{Add, Deref, Index, IndexMut};
 
-pub struct Indexable {
+pub struct _Indexable {
     data: [u8; 3],
 }
 
-impl Index<usize> for Indexable {
+impl Index<usize> for _Indexable {
     type Output = u8;
 
-    //~ MONO_ITEM fn <Indexable as std::ops::Index<usize>>::index
+    //~ MONO_ITEM fn <_Indexable as std::ops::Index<usize>>::index
     fn index(&self, index: usize) -> &Self::Output {
         if index >= 3 { &self.data[0] } else { &self.data[index] }
     }
 }
 
-impl IndexMut<usize> for Indexable {
-    //~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut
+impl IndexMut<usize> for _Indexable {
+    //~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut
     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
         if index >= 3 { &mut self.data[0] } else { &mut self.data[index] }
     }
 }
 
-//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::eq
-//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne
+//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq
+//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne
 #[derive(PartialEq)]
-pub struct Equatable(u32);
+pub struct _Equatable(u32);
 
-impl Add<u32> for Equatable {
+impl Add<u32> for _Equatable {
     type Output = u32;
 
-    //~ MONO_ITEM fn <Equatable as std::ops::Add<u32>>::add
+    //~ MONO_ITEM fn <_Equatable as std::ops::Add<u32>>::add
     fn add(self, rhs: u32) -> u32 {
         self.0 + rhs
     }
 }
 
-impl Deref for Equatable {
+impl Deref for _Equatable {
     type Target = u32;
 
-    //~ MONO_ITEM fn <Equatable as std::ops::Deref>::deref
+    //~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref
     fn deref(&self) -> &Self::Target {
         &self.0
     }
diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs
index 71f2dd42ec222..835cc7393e51e 100644
--- a/tests/codegen/align-byval-alignment-mismatch.rs
+++ b/tests/codegen/align-byval-alignment-mismatch.rs
@@ -1,9 +1,9 @@
 // ignore-tidy-linelength
 //@ revisions:i686-linux x86_64-linux
 
-//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -C panic=abort
 //@[i686-linux] needs-llvm-components: x86
-//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu -C panic=abort
 //@[x86_64-linux] needs-llvm-components: x86
 
 // Tests that we correctly copy arguments into allocas when the alignment of the byval argument
diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
index 2d9efb52c7cfa..708347075640b 100644
--- a/tests/codegen/avr/avr-func-addrspace.rs
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib
+//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort
 //@ needs-llvm-components: avr
 
 // This test validates that function pointers can be stored in global variables
diff --git a/tests/codegen/catch-unwind.rs b/tests/codegen/catch-unwind.rs
index 4e1f9a88e9573..48ad486fa03a6 100644
--- a/tests/codegen/catch-unwind.rs
+++ b/tests/codegen/catch-unwind.rs
@@ -14,7 +14,6 @@
 //@ ignore-loongarch64 FIXME
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 extern "C" {
     fn bar();
diff --git a/tests/codegen/cffi/c-variadic.rs b/tests/codegen/cffi/c-variadic.rs
index 914d1623ed230..140d2f37f4693 100644
--- a/tests/codegen/cffi/c-variadic.rs
+++ b/tests/codegen/cffi/c-variadic.rs
@@ -4,7 +4,6 @@
 
 #![crate_type = "lib"]
 #![feature(c_variadic)]
-#![feature(c_unwind)]
 #![no_std]
 use core::ffi::VaList;
 
diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs
index f690c9c0937ff..aee07b4eb8c68 100644
--- a/tests/codegen/debuginfo-inline-callsite-location.rs
+++ b/tests/codegen/debuginfo-inline-callsite-location.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -g -O
+//@ compile-flags: -g -O -C panic=abort
 
 // Check that each inline call site for the same function uses the same "sub-program" so that LLVM
 // can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail
diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
index 48c7ecf782429..0d9c7757883f7 100644
--- a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: arm
 //@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
index 8bb2122946fca..8d2745ba2f7ae 100644
--- a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
+++ b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
@@ -4,7 +4,6 @@
 // when the code is compiled with `panic=abort`.
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]]
 #[no_mangle]
diff --git a/tests/codegen/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs
index 99763943a6acf..46c08b5fc4ff4 100644
--- a/tests/codegen/unwind-abis/c-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/c-unwind-abi.rs
@@ -6,7 +6,6 @@
 // to prevent LLVM from inferring the attribute.
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
 #[no_mangle]
diff --git a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
index 78dbb55b35a21..8e643d6ce4947 100644
--- a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
@@ -6,7 +6,6 @@
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
 #[no_mangle]
diff --git a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
index 3cbeaf51d9600..4c7b2856e2e45 100644
--- a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
deleted file mode 100644
index a7f7f2fb77f71..0000000000000
--- a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ compile-flags: -C opt-level=0
-//@ needs-unwind
-
-#![crate_type = "lib"]
-
-// We disable optimizations to prevent LLVM from inferring the attribute.
-
-extern "C" {
-    fn bar();
-}
-
-// CHECK-NOT: Function Attrs:{{.*}}nounwind
-pub unsafe extern "C" fn foo() {
-    bar();
-}
-
-// Note that this test will get removed when `C-unwind` is fully stabilized
diff --git a/tests/codegen/unwind-abis/nounwind.rs b/tests/codegen/unwind-abis/nounwind.rs
index 80bf8d6709139..e40ed48ca737f 100644
--- a/tests/codegen/unwind-abis/nounwind.rs
+++ b/tests/codegen/unwind-abis/nounwind.rs
@@ -2,7 +2,6 @@
 //@ needs-unwind
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // We disable optimizations to prevent LLVM from inferring the attribute.
 
diff --git a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
index ffb235cd11681..ffc11d1faef8c 100644
--- a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs
index 1dd0e9bbbec7d..5f9102483464b 100644
--- a/tests/codegen/unwind-abis/system-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/system-unwind-abi.rs
@@ -6,7 +6,6 @@
 // optimizations above to prevent LLVM from inferring the attribute.
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
 #[no_mangle]
diff --git a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
index 9824009dc5592..c869ca7e2b825 100644
--- a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
index a96f4d5a350c1..19b23ee47ba84 100644
--- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
index 9929e3e3703de..b420f67ca9b70 100644
--- a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind, abi_vectorcall)]
+#![feature(no_core, lang_items, abi_vectorcall)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs
index a45a94f628d15..2697d3cbcd68e 100644
--- a/tests/codegen/unwind-abis/win64-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/win64-unwind-abi.rs
@@ -1,7 +1,7 @@
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind)]
+#![feature(no_core, lang_items)]
 #[lang = "sized"]
 trait Sized {}
 
diff --git a/tests/codegen/unwind-and-panic-abort.rs b/tests/codegen/unwind-and-panic-abort.rs
index 430502308cf0d..8efa140058ad1 100644
--- a/tests/codegen/unwind-and-panic-abort.rs
+++ b/tests/codegen/unwind-and-panic-abort.rs
@@ -1,7 +1,6 @@
 //@ compile-flags: -C panic=abort
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 extern "C-unwind" {
     fn bar();
diff --git a/tests/codegen/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs
index ea59748b3bcd2..e692fd1a54722 100644
--- a/tests/codegen/unwind-extern-exports.rs
+++ b/tests/codegen/unwind-extern-exports.rs
@@ -2,7 +2,6 @@
 //@ needs-unwind
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 // Make sure these all do *not* get the attribute.
 // We disable optimizations to prevent LLVM from inferring the attribute.
diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs
index 790e4def8b363..dfae8aae64a51 100644
--- a/tests/codegen/unwind-extern-imports.rs
+++ b/tests/codegen/unwind-extern-imports.rs
@@ -2,7 +2,6 @@
 //@ needs-unwind
 
 #![crate_type = "lib"]
-#![feature(c_unwind)]
 
 extern "C" {
     // CHECK: Function Attrs:{{.*}}nounwind
diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map
index 5673fa98ca606..15156ec9811b1 100644
--- a/tests/coverage/abort.cov-map
+++ b/tests/coverage/abort.cov-map
@@ -1,5 +1,5 @@
 Function name: abort::main
-Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
+Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 10
@@ -14,7 +14,7 @@ Number of expressions: 10
 - expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3)
 - expression 9 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 13
-- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 27)
+- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
     = (c0 + (c1 + c2))
 - Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25)
@@ -36,13 +36,13 @@ Number of file 0 mappings: 13
 - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)
 
 Function name: abort::might_abort
-Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02]
+Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 3
-- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 20)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2)
     = (c0 - c1)
diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage
index b658a65625912..29e3ad5eda7aa 100644
--- a/tests/coverage/abort.coverage
+++ b/tests/coverage/abort.coverage
@@ -1,4 +1,3 @@
-   LL|       |#![feature(c_unwind)]
    LL|       |#![allow(unused_assignments)]
    LL|       |
    LL|     12|extern "C" fn might_abort(should_abort: bool) {
diff --git a/tests/coverage/abort.rs b/tests/coverage/abort.rs
index 649e8e52a490e..6c06a3f9d8750 100644
--- a/tests/coverage/abort.rs
+++ b/tests/coverage/abort.rs
@@ -1,4 +1,3 @@
-#![feature(c_unwind)]
 #![allow(unused_assignments)]
 
 extern "C" fn might_abort(should_abort: bool) {
diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
index 1bdb634757120..827a1b7ce67d5 100644
--- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
+++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
@@ -5,7 +5,7 @@
 
 use std::path::PathBuf;
 
-use run_make_support::{aux_build, rustc};
+use run_make_support::{aux_build, rustc, source_root};
 
 fn main() {
     aux_build().input("stable.rs").emit("metadata").run();
@@ -17,7 +17,7 @@ fn main() {
         rustc().input("main.rs").emit("metadata").extern_("stable", &stable_path).command_output();
 
     let stderr = String::from_utf8_lossy(&output.stderr);
-    let version = include_str!(concat!(env!("S"), "/src/version"));
+    let version = std::fs::read_to_string(source_root().join("src/version")).unwrap();
     let expected_string = format!("stable since {}", version.trim());
     assert!(stderr.contains(&expected_string));
 }
diff --git a/tests/run-make/forced-unwind-terminate-pof/foo.rs b/tests/run-make/forced-unwind-terminate-pof/foo.rs
index 0a51287313f6e..3a84784621708 100644
--- a/tests/run-make/forced-unwind-terminate-pof/foo.rs
+++ b/tests/run-make/forced-unwind-terminate-pof/foo.rs
@@ -1,6 +1,5 @@
 // Tests that forced unwind through POF Rust frames wouldn't trigger our terminating guards.
 
-#![feature(c_unwind)]
 #![no_main]
 
 extern "C-unwind" {
diff --git a/tests/ui/asm/x86_64/may_unwind.rs b/tests/ui/asm/x86_64/may_unwind.rs
index 3b2c1edcd4786..d3a2916df9db6 100644
--- a/tests/ui/asm/x86_64/may_unwind.rs
+++ b/tests/ui/asm/x86_64/may_unwind.rs
@@ -16,7 +16,7 @@ impl Drop for Foo<'_> {
     }
 }
 
-extern "C" fn panicky() {
+extern "C-unwind" fn panicky() {
     resume_unwind(Box::new(()));
 }
 
diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
new file mode 100644
index 0000000000000..ce365d1a8b1c8
--- /dev/null
+++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
@@ -0,0 +1,7 @@
+//@ build-pass
+#![feature(unsafe_attributes)]
+
+#[cfg_attr(all(), unsafe(no_mangle))]
+fn a() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
new file mode 100644
index 0000000000000..774ce86c0960c
--- /dev/null
+++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
@@ -0,0 +1,6 @@
+#![feature(unsafe_attributes)]
+
+#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)`
+struct Foo;
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr
new file mode 100644
index 0000000000000..fc0daf16790a8
--- /dev/null
+++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr
@@ -0,0 +1,8 @@
+error: traits in `#[derive(...)]` don't accept `unsafe(...)`
+  --> $DIR/derive-unsafe-attributes.rs:3:10
+   |
+LL | #[derive(unsafe(Debug))]
+   |          ^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
new file mode 100644
index 0000000000000..a6c0ea578f25a
--- /dev/null
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
@@ -0,0 +1,9 @@
+#![feature(unsafe_attributes)]
+
+#[unsafe(unsafe(no_mangle))]
+//~^ ERROR expected identifier, found keyword `unsafe`
+//~| ERROR cannot find attribute `r#unsafe` in this scope
+//~| ERROR `r#unsafe` is not an unsafe attribute
+fn a() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
new file mode 100644
index 0000000000000..1c07a5bf8baa0
--- /dev/null
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
@@ -0,0 +1,27 @@
+error: expected identifier, found keyword `unsafe`
+  --> $DIR/double-unsafe-attributes.rs:3:10
+   |
+LL | #[unsafe(unsafe(no_mangle))]
+   |          ^^^^^^ expected identifier, found keyword
+   |
+help: escape `unsafe` to use it as an identifier
+   |
+LL | #[unsafe(r#unsafe(no_mangle))]
+   |          ++
+
+error: cannot find attribute `r#unsafe` in this scope
+  --> $DIR/double-unsafe-attributes.rs:3:10
+   |
+LL | #[unsafe(unsafe(no_mangle))]
+   |          ^^^^^^
+
+error: `r#unsafe` is not an unsafe attribute
+  --> $DIR/double-unsafe-attributes.rs:3:3
+   |
+LL | #[unsafe(unsafe(no_mangle))]
+   |   ^^^^^^
+   |
+   = note: extraneous unsafe is not allowed in attributes
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs
new file mode 100644
index 0000000000000..e7620a18048e4
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs
@@ -0,0 +1,7 @@
+//@ build-pass
+#![feature(unsafe_attributes)]
+
+#[unsafe(no_mangle)]
+fn a() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
new file mode 100644
index 0000000000000..67db36afd2e69
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
@@ -0,0 +1,6 @@
+#![feature(unsafe_attributes)]
+
+#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
+struct Foo {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
new file mode 100644
index 0000000000000..0602af34e4f64
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
@@ -0,0 +1,10 @@
+error: `repr` is not an unsafe attribute
+  --> $DIR/unsafe-safe-attribute.rs:3:3
+   |
+LL | #[unsafe(repr(C))]
+   |   ^^^^^^
+   |
+   = note: extraneous unsafe is not allowed in attributes
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
new file mode 100644
index 0000000000000..ff2eb61b40538
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
@@ -0,0 +1,8 @@
+#![feature(unsafe_attributes)]
+
+#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
+    message = "testing",
+))]
+trait Foo {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
new file mode 100644
index 0000000000000..584dacf4d8c91
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
@@ -0,0 +1,10 @@
+error: `diagnostic::on_unimplemented` is not an unsafe attribute
+  --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3
+   |
+LL | #[unsafe(diagnostic::on_unimplemented(
+   |   ^^^^^^
+   |
+   = note: extraneous unsafe is not allowed in attributes
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/coherence/re-rebalance-coherence.rs b/tests/ui/coherence/re-rebalance-coherence.rs
index 9c176d5b1b12b..5383a634617f4 100644
--- a/tests/ui/coherence/re-rebalance-coherence.rs
+++ b/tests/ui/coherence/re-rebalance-coherence.rs
@@ -4,6 +4,7 @@
 extern crate re_rebalance_coherence_lib as lib;
 use lib::*;
 
+#[allow(dead_code)]
 struct Oracle;
 impl Backend for Oracle {}
 impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
diff --git a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
index c23187598bceb..4bf2fa761eae8 100644
--- a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
+++ b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
@@ -2,6 +2,7 @@
 
 //@ run-pass
 
+#[allow(dead_code)]
 #[repr(C)]
 pub struct Loaf<T: Sized, const N: usize = 1> {
     head: [T; N],
diff --git a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
index 5d2198f50ad92..50a6102c605a9 100644
--- a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
+++ b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
@@ -16,7 +16,8 @@ impl BlockCipher for BarCipher {
     const BLOCK_SIZE: usize = 32;
 }
 
-pub struct Block<C>(#[allow(dead_code)] C);
+#[allow(dead_code)]
+pub struct Block<C>(C);
 
 pub fn test<C: BlockCipher, const M: usize>()
 where
diff --git a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
index 419d605d0c875..35c41ae461520 100644
--- a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
+++ b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
@@ -6,6 +6,7 @@
 
 use std::mem::MaybeUninit;
 
+#[allow(dead_code)]
 #[repr(transparent)]
 pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
 
diff --git a/tests/ui/consts/const-eval/unwind-abort.rs b/tests/ui/consts/const-eval/unwind-abort.rs
index 57959e7db6ad9..26113e238883d 100644
--- a/tests/ui/consts/const-eval/unwind-abort.rs
+++ b/tests/ui/consts/const-eval/unwind-abort.rs
@@ -1,4 +1,4 @@
-#![feature(c_unwind, const_extern_fn)]
+#![feature(const_extern_fn)]
 
 const extern "C" fn foo() {
     panic!() //~ ERROR evaluation of constant value failed
diff --git a/tests/ui/consts/unwind-abort.rs b/tests/ui/consts/unwind-abort.rs
index 35db9152bd551..1dd33f327fb68 100644
--- a/tests/ui/consts/unwind-abort.rs
+++ b/tests/ui/consts/unwind-abort.rs
@@ -1,6 +1,6 @@
 //@ check-pass
 
-#![feature(c_unwind, const_extern_fn)]
+#![feature(const_extern_fn)]
 
 // We don't unwind in const-eval anyways.
 const extern "C" fn foo() {
diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
index 6ab1fb7b039bd..885dacc727af6 100644
--- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
+++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
@@ -1,9 +1,9 @@
 #![forbid(dead_code)]
 
 #[derive(Debug)]
-pub struct Whatever {
+pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
     pub field0: (),
-    field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
+    field1: (),
     field2: (),
     field3: (),
     field4: (),
diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
index e9b757b6bae72..e10d28ad03a4e 100644
--- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
+++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
@@ -1,19 +1,9 @@
-error: fields `field1`, `field2`, `field3`, and `field4` are never read
-  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
+error: struct `Whatever` is never constructed
+  --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
    |
 LL | pub struct Whatever {
-   |            -------- fields in this struct
-LL |     pub field0: (),
-LL |     field1: (),
-   |     ^^^^^^
-LL |     field2: (),
-   |     ^^^^^^
-LL |     field3: (),
-   |     ^^^^^^
-LL |     field4: (),
-   |     ^^^^^^
+   |            ^^^^^^^^
    |
-   = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
 note: the lint level is defined here
   --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
    |
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
new file mode 100644
index 0000000000000..9eba415dda0e5
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
@@ -0,0 +1,8 @@
+#[unsafe(no_mangle)] //~ ERROR [E0658]
+extern "C" fn foo() {
+
+}
+
+fn main() {
+    foo();
+}
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
new file mode 100644
index 0000000000000..dfcea756b02b6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
@@ -0,0 +1,13 @@
+error[E0658]: `#[unsafe()]` markers for attributes are experimental
+  --> $DIR/feature-gate-unsafe-attributes.rs:1:3
+   |
+LL | #[unsafe(no_mangle)]
+   |   ^^^^^^
+   |
+   = note: see issue #123757 <https://github.com/rust-lang/rust/issues/123757> for more information
+   = help: add `#![feature(unsafe_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs
index ce9ef78ffcd9c..89ea9fbdcd8fe 100644
--- a/tests/ui/issues/issue-5708.rs
+++ b/tests/ui/issues/issue-5708.rs
@@ -44,6 +44,7 @@ pub trait MyTrait<T> {
     fn dummy(&self, t: T) -> T { panic!() }
 }
 
+#[allow(dead_code)]
 pub struct MyContainer<'a, T:'a> {
     foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
 }
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs
index ddcafedf7bc5f..3386dfa47470f 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs
@@ -46,11 +46,10 @@ struct SemiUsedStruct;
 impl SemiUsedStruct {
     fn la_la_la() {}
 }
-struct StructUsedAsField;
+struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed
 pub struct StructUsedInEnum;
 struct StructUsedInGeneric;
-pub struct PubStruct2 {
-    #[allow(dead_code)]
+pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed
     struct_used_as_field: *const StructUsedAsField
 }
 
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
index eb728b5b93055..b0163df8855cd 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
@@ -22,14 +22,26 @@ error: struct `PrivStruct` is never constructed
 LL | struct PrivStruct;
    |        ^^^^^^^^^^
 
+error: struct `StructUsedAsField` is never constructed
+  --> $DIR/lint-dead-code-1.rs:49:8
+   |
+LL | struct StructUsedAsField;
+   |        ^^^^^^^^^^^^^^^^^
+
+error: struct `PubStruct2` is never constructed
+  --> $DIR/lint-dead-code-1.rs:52:12
+   |
+LL | pub struct PubStruct2 {
+   |            ^^^^^^^^^^
+
 error: enum `priv_enum` is never used
-  --> $DIR/lint-dead-code-1.rs:64:6
+  --> $DIR/lint-dead-code-1.rs:63:6
    |
 LL | enum priv_enum { foo2, bar2 }
    |      ^^^^^^^^^
 
 error: variant `bar3` is never constructed
-  --> $DIR/lint-dead-code-1.rs:67:5
+  --> $DIR/lint-dead-code-1.rs:66:5
    |
 LL | enum used_enum {
    |      --------- variant in this enum
@@ -38,25 +50,25 @@ LL |     bar3
    |     ^^^^
 
 error: function `priv_fn` is never used
-  --> $DIR/lint-dead-code-1.rs:88:4
+  --> $DIR/lint-dead-code-1.rs:87:4
    |
 LL | fn priv_fn() {
    |    ^^^^^^^
 
 error: function `foo` is never used
-  --> $DIR/lint-dead-code-1.rs:93:4
+  --> $DIR/lint-dead-code-1.rs:92:4
    |
 LL | fn foo() {
    |    ^^^
 
 error: function `bar` is never used
-  --> $DIR/lint-dead-code-1.rs:98:4
+  --> $DIR/lint-dead-code-1.rs:97:4
    |
 LL | fn bar() {
    |    ^^^
 
 error: function `baz` is never used
-  --> $DIR/lint-dead-code-1.rs:102:4
+  --> $DIR/lint-dead-code-1.rs:101:4
    |
 LL | fn baz() -> impl Copy {
    |    ^^^
@@ -67,5 +79,5 @@ error: struct `Bar` is never constructed
 LL |     pub struct Bar;
    |                ^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/lint/dead-code/unused-assoc-const.rs b/tests/ui/lint/dead-code/unused-assoc-const.rs
new file mode 100644
index 0000000000000..36e8315ad3605
--- /dev/null
+++ b/tests/ui/lint/dead-code/unused-assoc-const.rs
@@ -0,0 +1,20 @@
+#![deny(dead_code)]
+
+trait Trait {
+    const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used
+    const USED_CONST: i32;
+
+    fn foo(&self) {}
+}
+
+pub struct T(());
+
+impl Trait for T {
+    const UNUSED_CONST: i32 = 0;
+    const USED_CONST: i32 = 1;
+}
+
+fn main() {
+    T(()).foo();
+    T::USED_CONST;
+}
diff --git a/tests/ui/lint/dead-code/unused-assoc-const.stderr b/tests/ui/lint/dead-code/unused-assoc-const.stderr
new file mode 100644
index 0000000000000..78296d706638b
--- /dev/null
+++ b/tests/ui/lint/dead-code/unused-assoc-const.stderr
@@ -0,0 +1,16 @@
+error: associated constant `UNUSED_CONST` is never used
+  --> $DIR/unused-assoc-const.rs:4:11
+   |
+LL | trait Trait {
+   |       ----- associated constant in this trait
+LL |     const UNUSED_CONST: i32;
+   |           ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-assoc-const.rs:1:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/dead-code/unused-pub-struct.rs b/tests/ui/lint/dead-code/unused-pub-struct.rs
new file mode 100644
index 0000000000000..aaf4dd612de4d
--- /dev/null
+++ b/tests/ui/lint/dead-code/unused-pub-struct.rs
@@ -0,0 +1,48 @@
+#![deny(dead_code)]
+
+pub struct NotLint1(());
+pub struct NotLint2(std::marker::PhantomData<i32>);
+
+pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed
+
+impl NeverConstructed {
+    pub fn not_construct_self(&self) {}
+}
+
+impl Clone for NeverConstructed {
+    fn clone(&self) -> NeverConstructed {
+        NeverConstructed(0)
+    }
+}
+
+pub trait Trait {
+    fn not_construct_self(&self);
+}
+
+impl Trait for NeverConstructed {
+    fn not_construct_self(&self) {
+        self.0;
+    }
+}
+
+pub struct Constructed(i32);
+
+impl Constructed {
+    pub fn construct_self() -> Self {
+        Constructed(0)
+    }
+}
+
+impl Clone for Constructed {
+    fn clone(&self) -> Constructed {
+        Constructed(0)
+    }
+}
+
+impl Trait for Constructed {
+    fn not_construct_self(&self) {
+        self.0;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-pub-struct.stderr b/tests/ui/lint/dead-code/unused-pub-struct.stderr
new file mode 100644
index 0000000000000..3667ddb97bd3e
--- /dev/null
+++ b/tests/ui/lint/dead-code/unused-pub-struct.stderr
@@ -0,0 +1,14 @@
+error: struct `NeverConstructed` is never constructed
+  --> $DIR/unused-pub-struct.rs:6:12
+   |
+LL | pub struct NeverConstructed(i32);
+   |            ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-pub-struct.rs:1:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/panics/abort-on-panic.rs b/tests/ui/panics/abort-on-panic.rs
index 5736ecf868566..feccefb253768 100644
--- a/tests/ui/panics/abort-on-panic.rs
+++ b/tests/ui/panics/abort-on-panic.rs
@@ -4,7 +4,6 @@
 //@[next] compile-flags: -Znext-solver
 
 #![allow(unused_must_use)]
-#![feature(c_unwind)]
 #![feature(panic_always_abort)]
 // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
 // we never unwind through them.
diff --git a/tests/ui/panics/panic-in-ffi.rs b/tests/ui/panics/panic-in-ffi.rs
index 6f54acb3e045d..88f45f9a871d7 100644
--- a/tests/ui/panics/panic-in-ffi.rs
+++ b/tests/ui/panics/panic-in-ffi.rs
@@ -7,7 +7,6 @@
 //@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
 //@ needs-unwind
 //@ ignore-emscripten "RuntimeError" junk in output
-#![feature(c_unwind)]
 
 extern "C" fn panic_in_ffi() {
     panic!("Test");
diff --git a/tests/ui/panics/panic-in-ffi.run.stderr b/tests/ui/panics/panic-in-ffi.run.stderr
index a92a66c57fd7d..596355399c801 100644
--- a/tests/ui/panics/panic-in-ffi.run.stderr
+++ b/tests/ui/panics/panic-in-ffi.run.stderr
@@ -1,4 +1,4 @@
-thread 'main' panicked at $DIR/panic-in-ffi.rs:13:5:
+thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5:
 Test
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
index a851300a9828e..e9c89807fa566 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
@@ -1,7 +1,8 @@
 // Regression test for issues #100790 and #106439.
 //@ run-rustfix
 
-pub struct Example(#[allow(dead_code)] usize)
+#[allow(dead_code)]
+pub struct Example(usize)
 where
     (): Sized;
 //~^^^ ERROR where clauses are not allowed before tuple struct bodies
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
index 10f435859f15a..3bd0f51ec2cbe 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
@@ -1,10 +1,11 @@
 // Regression test for issues #100790 and #106439.
 //@ run-rustfix
 
+#[allow(dead_code)]
 pub struct Example
 where
     (): Sized,
-(#[allow(dead_code)] usize);
+(usize);
 //~^^^ ERROR where clauses are not allowed before tuple struct bodies
 
 struct _Demo
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
index ddbf237e8662b..77eafa6bea336 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
@@ -1,23 +1,23 @@
 error: where clauses are not allowed before tuple struct bodies
-  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1
+  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1
    |
 LL |   pub struct Example
    |              ------- while parsing this tuple struct
 LL | / where
 LL | |     (): Sized,
    | |______________^ unexpected where clause
-LL |   (#[allow(dead_code)] usize);
-   |   --------------------------- the struct body
+LL |   (usize);
+   |   ------- the struct body
    |
 help: move the body before the where clause
    |
-LL ~ pub struct Example(#[allow(dead_code)] usize)
+LL ~ pub struct Example(usize)
 LL | where
 LL ~     (): Sized;
    |
 
 error: where clauses are not allowed before tuple struct bodies
-  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1
+  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1
    |
 LL |   struct _Demo
    |          ----- while parsing this tuple struct
diff --git a/tests/ui/pub/pub-ident-struct-4.fixed b/tests/ui/pub/pub-ident-struct-4.fixed
index 5fedbb7243749..a62ece43eced3 100644
--- a/tests/ui/pub/pub-ident-struct-4.fixed
+++ b/tests/ui/pub/pub-ident-struct-4.fixed
@@ -1,6 +1,7 @@
 //@ run-rustfix
 
-pub struct T(#[allow(dead_code)] String);
+#[allow(dead_code)]
+pub struct T(String);
 //~^ ERROR missing `struct` for struct definition
 
 fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.rs b/tests/ui/pub/pub-ident-struct-4.rs
index 5c721c25a7815..0d56a31beaf1c 100644
--- a/tests/ui/pub/pub-ident-struct-4.rs
+++ b/tests/ui/pub/pub-ident-struct-4.rs
@@ -1,6 +1,7 @@
 //@ run-rustfix
 
-pub T(#[allow(dead_code)] String);
+#[allow(dead_code)]
+pub T(String);
 //~^ ERROR missing `struct` for struct definition
 
 fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr
index 5fbb02c8673ce..ec1367832113b 100644
--- a/tests/ui/pub/pub-ident-struct-4.stderr
+++ b/tests/ui/pub/pub-ident-struct-4.stderr
@@ -1,12 +1,12 @@
 error: missing `struct` for struct definition
-  --> $DIR/pub-ident-struct-4.rs:3:4
+  --> $DIR/pub-ident-struct-4.rs:4:4
    |
-LL | pub T(#[allow(dead_code)] String);
+LL | pub T(String);
    |    ^
    |
 help: add `struct` here to parse `T` as a public struct
    |
-LL | pub struct T(#[allow(dead_code)] String);
+LL | pub struct T(String);
    |     ++++++
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/regions/regions-issue-21422.rs b/tests/ui/regions/regions-issue-21422.rs
index 54beed9b3ac2b..67852a6f5de0d 100644
--- a/tests/ui/regions/regions-issue-21422.rs
+++ b/tests/ui/regions/regions-issue-21422.rs
@@ -5,6 +5,7 @@
 
 //@ pretty-expanded FIXME #23616
 
+#[allow(dead_code)]
 pub struct P<'a> {
     _ptr: *const &'a u8,
 }
diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs
index 19672e41c9a30..16439a7fedd3e 100644
--- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs
+++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs
@@ -3,8 +3,10 @@
 #![allow(unused_variables)]
 //@ pretty-expanded FIXME #23616
 
+#[allow(dead_code)]
 pub struct Fd(u32);
 
+#[allow(dead_code)]
 fn foo(a: u32) {}
 
 impl Drop for Fd {
diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs
index 97bc7d8414e7f..1074dbcd6e6b5 100644
--- a/tests/ui/structs-enums/uninstantiable-struct.rs
+++ b/tests/ui/structs-enums/uninstantiable-struct.rs
@@ -1,4 +1,5 @@
 //@ run-pass
-pub struct Z(#[allow(dead_code)] &'static Z);
+#[allow(dead_code)]
+pub struct Z(&'static Z);
 
 pub fn main() {}
diff --git a/tests/ui/suggestions/derive-clone-for-eq.fixed b/tests/ui/suggestions/derive-clone-for-eq.fixed
index 4dc362f947875..cf800c6e47d87 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.fixed
+++ b/tests/ui/suggestions/derive-clone-for-eq.fixed
@@ -1,6 +1,7 @@
 //@ run-rustfix
 // https://github.com/rust-lang/rust/issues/79076
 
+#[allow(dead_code)]
 #[derive(Clone, Eq)] //~ ERROR [E0277]
 pub struct Struct<T: std::clone::Clone>(T);
 
diff --git a/tests/ui/suggestions/derive-clone-for-eq.rs b/tests/ui/suggestions/derive-clone-for-eq.rs
index b3635000f1658..84736426bac0d 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.rs
+++ b/tests/ui/suggestions/derive-clone-for-eq.rs
@@ -1,6 +1,7 @@
 //@ run-rustfix
 // https://github.com/rust-lang/rust/issues/79076
 
+#[allow(dead_code)]
 #[derive(Clone, Eq)] //~ ERROR [E0277]
 pub struct Struct<T>(T);
 
diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr
index 6fae6e1316df0..54670fbffcfb9 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.stderr
+++ b/tests/ui/suggestions/derive-clone-for-eq.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: Clone` is not satisfied
-  --> $DIR/derive-clone-for-eq.rs:4:17
+  --> $DIR/derive-clone-for-eq.rs:5:17
    |
 LL | #[derive(Clone, Eq)]
    |                 ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
    |
 note: required for `Struct<T>` to implement `PartialEq`
-  --> $DIR/derive-clone-for-eq.rs:7:19
+  --> $DIR/derive-clone-for-eq.rs:8:19
    |
 LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
    |         -----     ^^^^^^^^^^^^     ^^^^^^^^^
diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed
index 4a5a9483c20c8..ef07d55871e7e 100644
--- a/tests/ui/suggestions/option-content-move.fixed
+++ b/tests/ui/suggestions/option-content-move.fixed
@@ -1,4 +1,5 @@
 //@ run-rustfix
+#[allow(dead_code)]
 pub struct LipogramCorpora {
     selections: Vec<(char, Option<String>)>,
 }
@@ -17,6 +18,7 @@ impl LipogramCorpora {
     }
 }
 
+#[allow(dead_code)]
 pub struct LipogramCorpora2 {
     selections: Vec<(char, Result<String, String>)>,
 }
diff --git a/tests/ui/suggestions/option-content-move.rs b/tests/ui/suggestions/option-content-move.rs
index 90d05c7439970..5be6358fd6a57 100644
--- a/tests/ui/suggestions/option-content-move.rs
+++ b/tests/ui/suggestions/option-content-move.rs
@@ -1,4 +1,5 @@
 //@ run-rustfix
+#[allow(dead_code)]
 pub struct LipogramCorpora {
     selections: Vec<(char, Option<String>)>,
 }
@@ -17,6 +18,7 @@ impl LipogramCorpora {
     }
 }
 
+#[allow(dead_code)]
 pub struct LipogramCorpora2 {
     selections: Vec<(char, Result<String, String>)>,
 }
diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr
index a382a04344aeb..b4ec5b180d210 100644
--- a/tests/ui/suggestions/option-content-move.stderr
+++ b/tests/ui/suggestions/option-content-move.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
-  --> $DIR/option-content-move.rs:10:20
+  --> $DIR/option-content-move.rs:11:20
    |
 LL |                 if selection.1.unwrap().contains(selection.0) {
    |                    ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
@@ -19,7 +19,7 @@ LL |                 if selection.1.clone().unwrap().contains(selection.0) {
    |                               ++++++++
 
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
-  --> $DIR/option-content-move.rs:28:20
+  --> $DIR/option-content-move.rs:30:20
    |
 LL |                 if selection.1.unwrap().contains(selection.0) {
    |                    ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs
index 462b0bc5bb77f..0ae562c0d30a0 100644
--- a/tests/ui/traits/object/generics.rs
+++ b/tests/ui/traits/object/generics.rs
@@ -7,6 +7,7 @@ pub trait Trait2<A> {
     fn doit(&self) -> A;
 }
 
+#[allow(dead_code)]
 pub struct Impl<A1, A2, A3> {
     m1: marker::PhantomData<(A1,A2,A3)>,
     /*
diff --git a/tests/ui/unwind-abis/feature-gate-c_unwind.rs b/tests/ui/unwind-abis/feature-gate-c_unwind.rs
deleted file mode 100644
index 28ef7d57788ee..0000000000000
--- a/tests/ui/unwind-abis/feature-gate-c_unwind.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ ignore-test
-
-// After partial stabilisation, `c_unwind` only contains codegen behaviour changes
-// and are tested in `src/test/codegen/unwind-abis`