about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc/src/main.rs3
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs1
-rw-r--r--compiler/rustc_passes/src/entry.rs43
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_session/src/config/sigpipe.rs2
-rw-r--r--compiler/rustc_session/src/options.rs16
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs8
-rw-r--r--library/std/src/rt.rs2
-rw-r--r--library/std/src/sys/pal/unix/mod.rs12
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs18
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs7
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs10
-rw-r--r--src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md84
-rw-r--r--src/doc/unstable-book/src/language-features/unix-sigpipe.md62
-rw-r--r--src/tools/miri/src/eval.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs1
-rw-r--r--src/tools/rustdoc/main.rs3
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.rs4
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs4
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr17
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.rs5
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.stderr14
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs5
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr14
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.rs4
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs6
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs6
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.rs4
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs6
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr8
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs4
-rw-r--r--tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-unix_sigpipe.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-unix_sigpipe.stderr13
-rw-r--r--tests/ui/process/println-with-broken-pipe.rs4
-rw-r--r--tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs (renamed from tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs)4
-rw-r--r--tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs (renamed from tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs)4
-rw-r--r--tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs (renamed from tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs)0
-rw-r--r--tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs (renamed from tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs)0
-rw-r--r--tests/ui/runtime/on-broken-pipe/child-processes.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs)31
-rw-r--r--tests/ui/runtime/on-broken-pipe/default.rs4
-rw-r--r--tests/ui/runtime/on-broken-pipe/default.stderr2
-rw-r--r--tests/ui/runtime/on-broken-pipe/error.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs)6
-rw-r--r--tests/ui/runtime/on-broken-pipe/inherit.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs)10
-rw-r--r--tests/ui/runtime/on-broken-pipe/kill.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs)6
-rw-r--r--tests/ui/runtime/on-broken-pipe/no-flag-arg.rs4
-rw-r--r--tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr2
-rw-r--r--tests/ui/runtime/on-broken-pipe/not-used.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_ign.rs)6
-rw-r--r--tests/ui/runtime/on-broken-pipe/with-rustc_main.rs (renamed from tests/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs)5
-rw-r--r--tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs4
-rw-r--r--tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr2
64 files changed, 203 insertions, 372 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 434b978ae31..7ba58406ef1 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,5 +1,3 @@
-#![feature(unix_sigpipe)]
-
 // A note about jemalloc: rustc uses jemalloc when built for CI and
 // distribution. The obvious way to do this is with the `#[global_allocator]`
 // mechanism. However, for complicated reasons (see
@@ -34,7 +32,6 @@
 // https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
 // for an example of how to do so.
 
-#[unix_sigpipe = "sig_dfl"]
 fn main() {
     // See the comment at the top of this file for an explanation of this.
     #[cfg(feature = "jemalloc-sys")]
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 9d3aac66c41..9c33cc8ed0b 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -396,10 +396,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    gated!(
-        unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing,
-        EncodeCrossCrate::Yes, experimental!(unix_sigpipe)
-    ),
     ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e7d7a9f380b..fe50499db76 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -619,8 +619,6 @@ declare_features! (
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
-    /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
-    (unstable, unix_sigpipe, "1.65.0", Some(97889)),
     /// Allows unnamed fields of struct and union type
     (incomplete, unnamed_fields, "1.74.0", Some(49804)),
     /// Allows unsized fn parameters.
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index db150cc1f87..36f9dda7250 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
 use rustc_span::symbol::sym;
 use rustc_span::{FileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{
-    CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi,
+    CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
 };
 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
 use std::collections::{BTreeMap, BTreeSet};
@@ -809,6 +809,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(no_profiler_runtime, true);
     tracked!(no_trait_vptr, true);
     tracked!(no_unique_section_names, true);
+    tracked!(on_broken_pipe, OnBrokenPipe::Kill);
     tracked!(oom, OomStrategy::Panic);
     tracked!(osx_rpath_install_name, true);
     tracked!(packed_bundled_libs, true);
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index a545c170297..8878310d6e9 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -695,9 +695,6 @@ passes_transparent_incompatible =
 passes_undefined_naked_function_abi =
     Rust ABI is unsupported in naked functions
 
-passes_unix_sigpipe_values =
-    valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
-
 passes_unknown_external_lang_item =
     unknown external lang item: `{$lang_item}`
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c403e9196fa..e60aa27dba2 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2523,7 +2523,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::automatically_derived,
         sym::start,
         sym::rustc_main,
-        sym::unix_sigpipe,
         sym::derive,
         sym::test,
         sym::test_case,
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 438c583db49..d52092f2aa9 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -12,8 +12,7 @@ use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
 use crate::errors::{
-    AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
-    MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
+    AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
 };
 
 struct EntryContext<'tcx> {
@@ -67,11 +66,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
     );
     match entry_point_type {
-        EntryPointType::None => {
-            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
-            }
-        }
+        EntryPointType::None => (),
         _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
             for attr in [sym::start, sym::rustc_main] {
                 if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
@@ -81,9 +76,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
-            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
-            }
             ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
         }
         EntryPointType::RustcMainAttr => {
@@ -98,9 +90,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
             }
         }
         EntryPointType::Start => {
-            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
-            }
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
             } else {
@@ -120,7 +109,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
         Some((def_id.to_def_id(), EntryFnType::Start))
     } else if let Some((local_def_id, _)) = visitor.attr_main_fn {
         let def_id = local_def_id.to_def_id();
-        Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
+        Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
     } else {
         if let Some(main_def) = tcx.resolutions(()).main_def
             && let Some(def_id) = main_def.opt_fn_def_id()
@@ -133,31 +122,19 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
                 return None;
             }
 
-            return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }));
+            return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }));
         }
         no_main_err(tcx, visitor);
         None
     }
 }
 
-fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
-    if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) {
-        match (attr.value_str(), attr.meta_item_list()) {
-            (Some(sym::inherit), None) => sigpipe::INHERIT,
-            (Some(sym::sig_ign), None) => sigpipe::SIG_IGN,
-            (Some(sym::sig_dfl), None) => sigpipe::SIG_DFL,
-            (Some(_), None) => {
-                tcx.dcx().emit_err(UnixSigpipeValues { span: attr.span });
-                sigpipe::DEFAULT
-            }
-            _ => {
-                // Keep going so that `fn emit_malformed_attribute()` can print
-                // an excellent error message
-                sigpipe::DEFAULT
-            }
-        }
-    } else {
-        sigpipe::DEFAULT
+fn sigpipe(tcx: TyCtxt<'_>) -> u8 {
+    match tcx.sess.opts.unstable_opts.on_broken_pipe {
+        rustc_target::spec::OnBrokenPipe::Default => sigpipe::DEFAULT,
+        rustc_target::spec::OnBrokenPipe::Kill => sigpipe::SIG_DFL,
+        rustc_target::spec::OnBrokenPipe::Error => sigpipe::SIG_IGN,
+        rustc_target::spec::OnBrokenPipe::Inherit => sigpipe::INHERIT,
     }
 }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 03a607348e8..743faf54560 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1259,13 +1259,6 @@ pub struct ExternMain {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(passes_unix_sigpipe_values)]
-pub struct UnixSigpipeValues {
-    #[primary_span]
-    pub span: Span,
-}
-
 pub struct NoMainErr {
     pub sp: Span,
     pub crate_name: Symbol,
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ad66e5e1c2b..f2bdabbf394 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2909,7 +2909,9 @@ pub(crate) mod dep_tracking {
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_span::RealFileName;
-    use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi};
+    use rustc_target::spec::{
+        CodeModel, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
+    };
     use rustc_target::spec::{
         RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
     };
@@ -2973,6 +2975,7 @@ pub(crate) mod dep_tracking {
         InstrumentXRay,
         CrateType,
         MergeFunctions,
+        OnBrokenPipe,
         PanicStrategy,
         RelroLevel,
         OptLevel,
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
index 1fadc75cfd0..1830ee03485 100644
--- a/compiler/rustc_session/src/config/sigpipe.rs
+++ b/compiler/rustc_session/src/config/sigpipe.rs
@@ -1,6 +1,6 @@
 //! NOTE: Keep these constants in sync with `library/std/src/sys/pal/unix/mod.rs`!
 
-/// The default value if `#[unix_sigpipe]` is not specified. This resolves
+/// The default value if `-Zon-broken-pipe=...` is not specified. This resolves
 /// to `SIG_IGN` in `library/std/src/sys/pal/unix/mod.rs`.
 ///
 /// Note that `SIG_IGN` has been the Rust default since 2014. See
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7355e5b6953..65660286dd7 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -12,7 +12,7 @@ use rustc_span::edition::Edition;
 use rustc_span::RealFileName;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{
-    CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet, WasmCAbi,
+    CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, SanitizerSet, WasmCAbi,
 };
 use rustc_target::spec::{
     RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@@ -378,6 +378,7 @@ mod desc {
     pub const parse_time_passes_format: &str = "`text` (default) or `json`";
     pub const parse_passes: &str = "a space-separated list of passes, or `all`";
     pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` or `abort`";
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
@@ -708,6 +709,17 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
+        match v {
+            // OnBrokenPipe::Default can't be explicitly specified
+            Some("kill") => *slot = OnBrokenPipe::Kill,
+            Some("error") => *slot = OnBrokenPipe::Error,
+            Some("inherit") => *slot = OnBrokenPipe::Inherit,
+            _ => return false,
+        }
+        true
+    }
+
     pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
         match v {
             Some("panic") => *slot = OomStrategy::Panic,
@@ -1833,6 +1845,8 @@ options! {
         "do not use unique names for text and data sections when -Z function-sections is used"),
     normalize_docs: bool = (false, parse_bool, [TRACKED],
         "normalize associated items in rustdoc when generating documentation"),
+    on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
+        "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
     oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
         "panic strategy for out-of-memory handling"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7fe94c2e82b..9c556f1152a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1936,7 +1936,6 @@ symbols! {
         unit,
         universal_impl_trait,
         unix,
-        unix_sigpipe,
         unlikely,
         unmarked_api,
         unnamed_fields,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index bd347c1b4b3..cbb248a0fc2 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -778,6 +778,14 @@ pub enum PanicStrategy {
     Abort,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
+pub enum OnBrokenPipe {
+    Default,
+    Kill,
+    Error,
+    Inherit,
+}
+
 impl PanicStrategy {
     pub fn desc(&self) -> &str {
         match *self {
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 59e118f81ab..46f691d7b75 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -74,7 +74,7 @@ macro_rules! rtunwrap {
 //
 // Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
 // `SIG_IGN`. Applications have good reasons to want a different behavior
-// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
+// though, so there is a `-Zon-broken-pipe` compiler flag that
 // can be used to select how `SIGPIPE` shall be setup (if changed at all) before
 // `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
 // for more info.
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 01d7fb31d7d..1ac5729c02f 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -55,8 +55,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     // want!
     //
     // Hence, we set SIGPIPE to ignore when the program starts up in order
-    // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
-    // alter this behavior.
+    // to prevent this problem. Use `-Zon-broken-pipe=...` to alter this
+    // behavior.
     reset_sigpipe(sigpipe);
 
     stack_overflow::init();
@@ -190,7 +190,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
                 _ => unreachable!(),
             };
             if sigpipe_attr_specified {
-                UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
+                ON_BROKEN_PIPE_FLAG_USED.store(true, crate::sync::atomic::Ordering::Relaxed);
             }
             if let Some(handler) = handler {
                 rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
@@ -210,7 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     target_os = "fuchsia",
     target_os = "horizon",
 )))]
-static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
+static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
     crate::sync::atomic::AtomicBool::new(false);
 
 #[cfg(not(any(
@@ -219,8 +219,8 @@ static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
     target_os = "fuchsia",
     target_os = "horizon",
 )))]
-pub(crate) fn unix_sigpipe_attr_specified() -> bool {
-    UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
+pub(crate) fn on_broken_pipe_flag_used() -> bool {
+    ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
 }
 
 // SAFETY: must be called only once during runtime cleanup.
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index f2947161cd5..e2fca8c7e63 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -353,11 +353,11 @@ impl Command {
             // Inherit the signal mask from the parent rather than resetting it (i.e. do not call
             // pthread_sigmask).
 
-            // If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
-            // If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
+            // If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
+            // If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
             //
-            // #[unix_sigpipe] is an opportunity to change the default here.
-            if !crate::sys::pal::unix_sigpipe_attr_specified() {
+            // -Zon-broken-pipe is an opportunity to change the default here.
+            if !crate::sys::pal::on_broken_pipe_flag_used() {
                 #[cfg(target_os = "android")] // see issue #88585
                 {
                     let mut action: libc::sigaction = mem::zeroed();
@@ -450,7 +450,7 @@ impl Command {
     ) -> io::Result<Option<Process>> {
         use crate::mem::MaybeUninit;
         use crate::sys::weak::weak;
-        use crate::sys::{self, cvt_nz, unix_sigpipe_attr_specified};
+        use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
 
         if self.get_gid().is_some()
             || self.get_uid().is_some()
@@ -612,11 +612,11 @@ impl Command {
             // Inherit the signal mask from this process rather than resetting it (i.e. do not call
             // posix_spawnattr_setsigmask).
 
-            // If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
-            // If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
+            // If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
+            // If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
             //
-            // #[unix_sigpipe] is an opportunity to change the default here.
-            if !unix_sigpipe_attr_specified() {
+            // -Zon-broken-pipe is an opportunity to change the default here.
+            if !on_broken_pipe_flag_used() {
                 let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
                 cvt(sigemptyset(default_set.as_mut_ptr()))?;
                 cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 1d46a158f9e..48a6602e2df 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1006,6 +1006,13 @@ pub fn rustc_cargo(
 
     cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");
 
+    // If the rustc output is piped to e.g. `head -n1` we want the process to be
+    // killed, rather than having an error bubble up and cause a panic.
+    // FIXME: Synthetic #[cfg(bootstrap)]. Remove when the bootstrap compiler supports it.
+    if compiler.stage != 0 {
+        cargo.rustflag("-Zon-broken-pipe=kill");
+    }
+
     // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
     // and may just be a time sink.
     if compiler.stage != 0 {
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 2e2c5e9e6f8..21344a4224e 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -471,7 +471,7 @@ impl Step for Rustdoc {
             features.push("jemalloc".to_string());
         }
 
-        let cargo = prepare_tool_cargo(
+        let mut cargo = prepare_tool_cargo(
             builder,
             build_compiler,
             Mode::ToolRustc,
@@ -482,6 +482,14 @@ impl Step for Rustdoc {
             features.as_slice(),
         );
 
+        // If the rustdoc output is piped to e.g. `head -n1` we want the process
+        // to be killed, rather than having an error bubble up and cause a
+        // panic.
+        // FIXME: Synthetic #[cfg(bootstrap)]. Remove when the bootstrap compiler supports it.
+        if build_compiler.stage > 0 {
+            cargo.rustflag("-Zon-broken-pipe=kill");
+        }
+
         let _guard = builder.msg_tool(
             Kind::Build,
             Mode::ToolRustc,
diff --git a/src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md b/src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md
new file mode 100644
index 00000000000..bdc175f3b0a
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md
@@ -0,0 +1,84 @@
+# `on-broken-pipe`
+
+--------------------
+
+The tracking issue for this feature is: [#97889]
+
+Note: The ui for this feature was previously an attribute named `#[unix_sigpipe = "..."]`.
+
+[#97889]: https://github.com/rust-lang/rust/issues/97889
+
+---
+
+
+## Overview
+
+The `-Zon-broken-pipe=...` compiler flag can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This flag is ignored on non-Unix targets. The flag can be used with three different values or be omitted entirely. It affects `SIGPIPE` before `fn main()` and before children get `exec()`'ed:
+
+| Compiler flag              | `SIGPIPE` before `fn main()` | `SIGPIPE` before child `exec()` |
+|----------------------------|------------------------------|---------------------------------|
+| not used                   | `SIG_IGN`                    | `SIG_DFL`                       |
+| `-Zon-broken-pipe=kill`    | `SIG_DFL`                    | not touched                     |
+| `-Zon-broken-pipe=error`   | `SIG_IGN`                    | not touched                     |
+| `-Zon-broken-pipe=inherit` | not touched                  | not touched                     |
+
+
+## `-Zon-broken-pipe` not used
+
+If `-Zon-broken-pipe` is not used, libstd will behave in the manner it has since 2014, before Rust 1.0. `SIGPIPE` will be set to `SIG_IGN` before `fn main()` and result in `EPIPE` errors which are converted to `std::io::ErrorKind::BrokenPipe`.
+
+When spawning child processes, `SIGPIPE` will be set to `SIG_DFL` before doing the underlying `exec()` syscall.
+
+
+## `-Zon-broken-pipe=kill`
+
+Set the `SIGPIPE` handler to `SIG_DFL` before invoking `fn main()`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
+
+When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_DFL` for `SIGPIPE`.
+
+### Example
+
+```rust,no_run
+fn main() {
+    loop {
+        println!("hello world");
+    }
+}
+```
+
+```console
+$ rustc -Zon-broken-pipe=kill main.rs
+$ ./main | head -n1
+hello world
+```
+
+## `-Zon-broken-pipe=error`
+
+Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
+
+When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_IGN` for `SIGPIPE`.
+
+### Example
+
+```rust,no_run
+fn main() {
+    loop {
+        println!("hello world");
+    }
+}
+```
+
+```console
+$ rustc -Zon-broken-pipe=error main.rs
+$ ./main | head -n1
+hello world
+thread 'main' panicked at library/std/src/io/stdio.rs:1118:9:
+failed printing to stdout: Broken pipe (os error 32)
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+```
+
+## `-Zon-broken-pipe=inherit`
+
+Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `-Zon-broken-pipe=kill`.
+
+When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_DFL` for `SIGPIPE`.
diff --git a/src/doc/unstable-book/src/language-features/unix-sigpipe.md b/src/doc/unstable-book/src/language-features/unix-sigpipe.md
deleted file mode 100644
index 7ed6a7de895..00000000000
--- a/src/doc/unstable-book/src/language-features/unix-sigpipe.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# `unix_sigpipe`
-
-The tracking issue for this feature is: [#97889]
-
-[#97889]: https://github.com/rust-lang/rust/issues/97889
-
----
-
-The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants:
-* `#[unix_sigpipe = "inherit"]`
-* `#[unix_sigpipe = "sig_dfl"]`
-* `#[unix_sigpipe = "sig_ign"]`
-
-## `#[unix_sigpipe = "inherit"]`
-
-Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`.
-
-## `#[unix_sigpipe = "sig_dfl"]`
-
-Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
-
-### Example
-
-```rust,no_run
-#![feature(unix_sigpipe)]
-#[unix_sigpipe = "sig_dfl"]
-fn main() { loop { println!("hello world"); } }
-```
-
-```bash
-% ./main | head -n 1
-hello world
-```
-
-## `#[unix_sigpipe = "sig_ign"]`
-
-Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
-
-This is what libstd has done by default since 2014. (However, see the note on child processes below.)
-
-### Example
-
-```rust,no_run
-#![feature(unix_sigpipe)]
-#[unix_sigpipe = "sig_ign"]
-fn main() { loop { println!("hello world"); } }
-```
-
-```bash
-% ./main | head -n 1
-hello world
-thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-```
-
-### Note on child processes
-
-When spawning child processes, the legacy Rust behavior if `#[unix_sigpipe]` is not specified is to
-reset `SIGPIPE` to `SIG_DFL`.
-
-If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of
-`SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior.
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 2242768a568..97c5e9a0eac 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -387,7 +387,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             let main_ptr = ecx.fn_ptr(FnVal::Instance(entry_instance));
 
             // Always using DEFAULT is okay since we don't support signals in Miri anyway.
-            // (This means we are effectively ignoring `#[unix_sigpipe]`.)
+            // (This means we are effectively ignoring `-Zon-broken-pipe`.)
             let sigpipe = rustc_session::config::sigpipe::DEFAULT;
 
             ecx.call_function(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index 55b9a1dfdcb..1fba2e2e4d3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -207,7 +207,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)),
     ungated!(start, Normal, template!(Word), WarnFollowing),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs
index b81f46d1211..5b499a1fa1f 100644
--- a/src/tools/rustdoc/main.rs
+++ b/src/tools/rustdoc/main.rs
@@ -1,6 +1,3 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_dfl"]
 fn main() {
     rustdoc::main()
 }
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.rs
deleted file mode 100644
index 5d95fc70e78..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe] //~ error: malformed `unix_sigpipe` attribute input
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.stderr
deleted file mode 100644
index c1b4470d54a..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-bare.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: malformed `unix_sigpipe` attribute input
-  --> $DIR/unix_sigpipe-bare.rs:3:1
-   |
-LL | #[unix_sigpipe]
-   | ^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs
deleted file mode 100644
index f5fa177f29c..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(unix_sigpipe)]
-#![unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute cannot be used at crate level
-
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr
deleted file mode 100644
index fdfa3018086..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: `unix_sigpipe` attribute cannot be used at crate level
-  --> $DIR/unix_sigpipe-crate.rs:2:1
-   |
-LL | #![unix_sigpipe = "sig_dfl"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | fn main() {}
-   |    ---- the inner attribute doesn't annotate this function
-   |
-help: perhaps you meant to use an outer attribute
-   |
-LL - #![unix_sigpipe = "sig_dfl"]
-LL + #[unix_sigpipe = "sig_dfl"]
-   |
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.rs
deleted file mode 100644
index 294cb38526b..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_ign"]
-#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.stderr
deleted file mode 100644
index c2a3b9f45f9..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-different-duplicates.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: multiple `unix_sigpipe` attributes
-  --> $DIR/unix_sigpipe-different-duplicates.rs:4:1
-   |
-LL | #[unix_sigpipe = "inherit"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unix_sigpipe-different-duplicates.rs:3:1
-   |
-LL | #[unix_sigpipe = "sig_ign"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs
deleted file mode 100644
index eccb23021b6..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "inherit"]
-#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr
deleted file mode 100644
index c86e54a1e53..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: multiple `unix_sigpipe` attributes
-  --> $DIR/unix_sigpipe-duplicates.rs:4:1
-   |
-LL | #[unix_sigpipe = "inherit"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unix_sigpipe-duplicates.rs:3:1
-   |
-LL | #[unix_sigpipe = "inherit"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.rs
deleted file mode 100644
index 462ae24a884..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe(sig_dfl)] //~ error: malformed `unix_sigpipe` attribute input
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.stderr
deleted file mode 100644
index a020f21e6ca..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-ident-list.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: malformed `unix_sigpipe` attribute input
-  --> $DIR/unix_sigpipe-ident-list.rs:3:1
-   |
-LL | #[unix_sigpipe(sig_dfl)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs
deleted file mode 100644
index 16731a4ba2c..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
-fn f() {}
-
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr
deleted file mode 100644
index fcdd5db8f29..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `unix_sigpipe` attribute can only be used on `fn main()`
-  --> $DIR/unix_sigpipe-non-main-fn.rs:3:1
-   |
-LL | #[unix_sigpipe = "sig_dfl"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs
deleted file mode 100644
index a2435258620..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(unix_sigpipe)]
-
-mod m {
-    #[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
-    fn main() {}
-}
-
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr
deleted file mode 100644
index 98afb62fdb4..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `unix_sigpipe` attribute can only be used on root `fn main()`
-  --> $DIR/unix_sigpipe-non-root-main.rs:4:5
-   |
-LL |     #[unix_sigpipe = "sig_dfl"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs
deleted file mode 100644
index 945b820f9e0..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(start)]
-#![feature(unix_sigpipe)]
-
-#[start]
-#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
-fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr
deleted file mode 100644
index 3d56b3655c9..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `unix_sigpipe` attribute can only be used on `fn main()`
-  --> $DIR/unix_sigpipe-start.rs:5:1
-   |
-LL | #[unix_sigpipe = "sig_dfl"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.rs
deleted file mode 100644
index 22326835623..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe("sig_dfl")] //~ error: malformed `unix_sigpipe` attribute input
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.stderr
deleted file mode 100644
index b62c086e360..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-str-list.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: malformed `unix_sigpipe` attribute input
-  --> $DIR/unix_sigpipe-str-list.rs:3:1
-   |
-LL | #[unix_sigpipe("sig_dfl")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs
deleted file mode 100644
index 662779c0821..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
-struct S;
-
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr
deleted file mode 100644
index a8fc51bdbc4..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `unix_sigpipe` attribute can only be used on `fn main()`
-  --> $DIR/unix_sigpipe-struct.rs:3:1
-   |
-LL | #[unix_sigpipe = "sig_dfl"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs
deleted file mode 100644
index 4ec25de00ec..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "wrong"] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
-fn main() {}
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr
deleted file mode 100644
index d750443e4a9..00000000000
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
-  --> $DIR/unix_sigpipe-wrong.rs:3:1
-   |
-LL | #[unix_sigpipe = "wrong"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/feature-gates/feature-gate-unix_sigpipe.rs b/tests/ui/feature-gates/feature-gate-unix_sigpipe.rs
deleted file mode 100644
index 46dc3f6cc17..00000000000
--- a/tests/ui/feature-gates/feature-gate-unix_sigpipe.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![crate_type = "bin"]
-
-#[unix_sigpipe = "inherit"] //~ the `#[unix_sigpipe]` attribute is an experimental feature
-fn main () {}
diff --git a/tests/ui/feature-gates/feature-gate-unix_sigpipe.stderr b/tests/ui/feature-gates/feature-gate-unix_sigpipe.stderr
deleted file mode 100644
index 88c18e72683..00000000000
--- a/tests/ui/feature-gates/feature-gate-unix_sigpipe.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[unix_sigpipe]` attribute is an experimental feature
-  --> $DIR/feature-gate-unix_sigpipe.rs:3:1
-   |
-LL | #[unix_sigpipe = "inherit"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #97889 <https://github.com/rust-lang/rust/issues/97889> for more information
-   = help: add `#![feature(unix_sigpipe)]` 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/process/println-with-broken-pipe.rs b/tests/ui/process/println-with-broken-pipe.rs
index 1df8c765cbd..798db3c0f8c 100644
--- a/tests/ui/process/println-with-broken-pipe.rs
+++ b/tests/ui/process/println-with-broken-pipe.rs
@@ -6,16 +6,14 @@
 //@ ignore-horizon
 //@ ignore-android
 //@ normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+//@ compile-flags: -Zon-broken-pipe=error
 
 // Test what the error message looks like when `println!()` panics because of
 // `std::io::ErrorKind::BrokenPipe`
 
-#![feature(unix_sigpipe)]
-
 use std::env;
 use std::process::{Command, Stdio};
 
-#[unix_sigpipe = "sig_ign"]
 fn main() {
     let mut args = env::args();
     let me = args.next().unwrap();
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs
index 7f95fa7ebbe..b179e484524 100644
--- a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_dfl.rs
@@ -1,8 +1,6 @@
 //@ aux-crate: sigpipe_utils=sigpipe-utils.rs
+//@ compile-flags: -Zon-broken-pipe=inherit
 
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "inherit"]
 fn main() {
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
 }
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs
index d96e8b8ef84..5ea435521ec 100644
--- a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-inherit-sig_ign.rs
@@ -1,8 +1,6 @@
 //@ aux-crate: sigpipe_utils=sigpipe-utils.rs
+//@ compile-flags: -Zon-broken-pipe=inherit
 
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "inherit"]
 fn main() {
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
 }
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
index 117f6134b4e..117f6134b4e 100644
--- a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs
index 3d93d50ca3f..3d93d50ca3f 100644
--- a/tests/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs b/tests/ui/runtime/on-broken-pipe/child-processes.rs
index 9d1bd9f9607..0da2347481b 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs
+++ b/tests/ui/runtime/on-broken-pipe/child-processes.rs
@@ -1,25 +1,20 @@
-//@ revisions: default sig_dfl sig_ign inherit
+//@ revisions: default error kill inherit
 //@ ignore-cross-compile because aux-bin does not yet support it
 //@ only-unix because SIGPIPE is a unix thing
 //@ run-pass
 //@ aux-bin:assert-sigpipe-disposition.rs
 //@ aux-crate:sigpipe_utils=sigpipe-utils.rs
+//@ [kill] compile-flags: -Zunstable-options -Zon-broken-pipe=kill
+//@ [error] compile-flags: -Zunstable-options -Zon-broken-pipe=error
+//@ [inherit] compile-flags: -Zunstable-options -Zon-broken-pipe=inherit
 
 // Checks the signal disposition of `SIGPIPE` in child processes, and in our own
-// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
-// the default. But there is a difference in how `SIGPIPE` is treated in child
-// processes with and without the attribute. Search for
-// `unix_sigpipe_attr_specified()` in the code base to learn more.
-
-#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
+// process for robustness.
 
 extern crate sigpipe_utils;
 
 use sigpipe_utils::*;
 
-#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
-#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
-#[cfg_attr(inherit, unix_sigpipe = "inherit")]
 fn main() {
     // By default we get SIG_IGN but the child gets SIG_DFL through an explicit
     // reset before exec:
@@ -27,18 +22,18 @@ fn main() {
     #[cfg(default)]
     let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
 
-    // With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too
-    // without any special code running before exec.
-    #[cfg(sig_dfl)]
+    // We get SIG_DFL and the child does too without any special code running
+    // before exec.
+    #[cfg(kill)]
     let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
 
-    // With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too
-    // without any special code running before exec.
-    #[cfg(sig_ign)]
+    // We get SIG_IGN and the child does too without any special code running
+    // before exec.
+    #[cfg(error)]
     let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
 
-    // With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too
-    // without any special code running before exec.
+    // We get SIG_DFL and the child does too without any special code running
+    // before exec.
     #[cfg(inherit)]
     let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
 
diff --git a/tests/ui/runtime/on-broken-pipe/default.rs b/tests/ui/runtime/on-broken-pipe/default.rs
new file mode 100644
index 00000000000..c10d1cfacc0
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/default.rs
@@ -0,0 +1,4 @@
+//@ compile-flags: -Zon-broken-pipe=default
+//@ check-fail
+
+fn main() {}
diff --git a/tests/ui/runtime/on-broken-pipe/default.stderr b/tests/ui/runtime/on-broken-pipe/default.stderr
new file mode 100644
index 00000000000..b90d7566cbb
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/default.stderr
@@ -0,0 +1,2 @@
+error: incorrect value `default` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected
+
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs b/tests/ui/runtime/on-broken-pipe/error.rs
index b0044f5e919..ab2036c2f41 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs
+++ b/tests/ui/runtime/on-broken-pipe/error.rs
@@ -1,12 +1,10 @@
-//@ revisions: with_feature without_feature
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
-
-#![cfg_attr(with_feature, feature(unix_sigpipe))]
+//@ compile-flags: -Zon-broken-pipe=error
 
 fn main() {
     extern crate sigpipe_utils;
 
-    // SIGPIPE shall be ignored since #[unix_sigpipe = "..."] is not used
+    // `-Zon-broken-pipe=error` is active, so we expect SIGPIPE to be ignored.
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
 }
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/tests/ui/runtime/on-broken-pipe/inherit.rs
index 3e63349edb7..64909b73528 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
+++ b/tests/ui/runtime/on-broken-pipe/inherit.rs
@@ -3,20 +3,20 @@
 //@ aux-bin: assert-inherit-sig_dfl.rs
 //@ aux-bin: assert-inherit-sig_ign.rs
 //@ run-pass
+//@ compile-flags: -Zon-broken-pipe=kill
 
-#![feature(rustc_private, unix_sigpipe)]
+#![feature(rustc_private)]
 
 extern crate libc;
 
 // By default the Rust runtime resets SIGPIPE to SIG_DFL before exec'ing child
-// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See
+// processes so opt-out of that with `-Zon-broken-pipe=kill`. See
 // https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384
-#[unix_sigpipe = "sig_dfl"]
 fn main() {
-    // First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"].
+    // First expect SIG_DFL in a child process with -`Zon-broken-pipe=inherit`.
     assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl");
 
-    // With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN.
+    // With SIG_IGN we expect `-Zon-broken-pipe=inherit` to also get SIG_IGN.
     unsafe {
         libc::signal(libc::SIGPIPE, libc::SIG_IGN);
     }
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs b/tests/ui/runtime/on-broken-pipe/kill.rs
index 30f2a9b1430..5dace6f1c6f 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs
+++ b/tests/ui/runtime/on-broken-pipe/kill.rs
@@ -1,13 +1,11 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
+//@ compile-flags: -Zon-broken-pipe=kill
 
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_dfl"]
 fn main() {
     extern crate sigpipe_utils;
 
-    // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE shall NOT be ignored, instead
+    // `-Zon-broken-pipe=kill` is active, so SIGPIPE shall NOT be ignored, instead
     // the default handler shall be installed
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
 }
diff --git a/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs
new file mode 100644
index 00000000000..2273291bfa7
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/no-flag-arg.rs
@@ -0,0 +1,4 @@
+//@ compile-flags: -Zon-broken-pipe
+//@ check-fail
+
+fn main() {}
diff --git a/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr b/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr
new file mode 100644
index 00000000000..3d3e12d303c
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr
@@ -0,0 +1,2 @@
+error: unstable option `on-broken-pipe` requires either `kill`, `error`, or `inherit` (Z on-broken-pipe=<value>)
+
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_ign.rs b/tests/ui/runtime/on-broken-pipe/not-used.rs
index ccd6c678660..e31236f2b3d 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-sig_ign.rs
+++ b/tests/ui/runtime/on-broken-pipe/not-used.rs
@@ -1,13 +1,9 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 
-#![feature(unix_sigpipe)]
-
-#[unix_sigpipe = "sig_ign"]
 fn main() {
     extern crate sigpipe_utils;
 
-    // #[unix_sigpipe = "sig_ign"] is active, so the legacy behavior of ignoring
-    // SIGPIPE shall be in effect
+    // SIGPIPE shall be ignored since `-Zon-broken-pipe` is not used
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
 }
diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
index 02a3f48f3b3..c1731200038 100644
--- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs
+++ b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
@@ -1,15 +1,14 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
+//@ compile-flags: -Zon-broken-pipe=kill
 
-#![feature(unix_sigpipe)]
 #![feature(rustc_attrs)]
 
-#[unix_sigpipe = "sig_dfl"]
 #[rustc_main]
 fn rustc_main() {
     extern crate sigpipe_utils;
 
-    // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE handler shall be
+    // `-Zon-broken-pipe=kill` is active, so SIGPIPE handler shall be
     // SIG_DFL. Note that we have a #[rustc_main], but it should still work.
     sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
 }
diff --git a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs
new file mode 100644
index 00000000000..14d0ac56b5a
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs
@@ -0,0 +1,4 @@
+//@ compile-flags: -Zon-broken-pipe=wrong
+//@ check-fail
+
+fn main() {}
diff --git a/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr
new file mode 100644
index 00000000000..3635418c845
--- /dev/null
+++ b/tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr
@@ -0,0 +1,2 @@
+error: incorrect value `wrong` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected
+