about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-26 15:47:26 +0000
committerbors <bors@rust-lang.org>2022-08-26 15:47:26 +0000
commit450e99f93795c81c1f2d10be27fb3a98be5b0cfc (patch)
tree271ef95ed18eedde35ed9af02366aeeb2eaba5b6
parent42fa8ac7236f4f78a82aeea543bdd445a59f02e0 (diff)
parentcf2c492ef8c87c049b4e3a62f43c841aafc88cba (diff)
downloadrust-450e99f93795c81c1f2d10be27fb3a98be5b0cfc.tar.gz
rust-450e99f93795c81c1f2d10be27fb3a98be5b0cfc.zip
Auto merge of #98051 - davidtwco:split-dwarf-stabilization, r=wesleywiser
session: stabilize split debuginfo on linux

Stabilize the `-Csplit-debuginfo` flag...

- ...on Linux for all values of the flag. Split DWARF has been implemented for a few months, hasn't had any bug reports and has had some promising benchmarking for incremental debug build performance.
- ..on other platforms for the default value. It doesn't make any sense that `-Csplit-debuginfo=packed` is unstable on Windows MSVC when that's the default behaviour, but keep the other values unstable.
-rw-r--r--compiler/rustc_session/src/config.rs7
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs104
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs7
-rw-r--r--compiler/rustc_target/src/spec/windows_msvc_base.rs3
-rw-r--r--src/bootstrap/builder.rs30
-rw-r--r--src/test/incremental/split_debuginfo_cached.rs4
-rw-r--r--src/test/incremental/split_debuginfo_mode.rs8
-rw-r--r--src/test/run-make-fulldeps/split-debuginfo/Makefile39
-rw-r--r--src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs3
-rw-r--r--src/tools/compiletest/src/runtest.rs7
14 files changed, 184 insertions, 60 deletions
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 68519c8fa82..162fc9aa0a6 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2423,13 +2423,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let pretty = parse_pretty(&unstable_opts, error_format);
 
-    if !unstable_opts.unstable_options
-        && !target_triple.triple().contains("apple")
-        && cg.split_debuginfo.is_some()
-    {
-        early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
-    }
-
     // Try to find a directory containing the Rust `src`, for more details see
     // the doc comment on the `real_rust_source_base_dir` field.
     let tmp_buf;
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 4972ae2014d..07dd8409487 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -31,7 +31,7 @@ use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
 use rustc_target::spec::{
-    SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+    DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
 };
 
 use std::cell::{self, RefCell};
@@ -670,8 +670,9 @@ impl Session {
             )
     }
 
+    /// Returns `true` if the target can use the current split debuginfo configuration.
     pub fn target_can_use_split_dwarf(&self) -> bool {
-        !self.target.is_like_windows && !self.target.is_like_osx
+        self.target.debuginfo_kind == DebuginfoKind::Dwarf
     }
 
     pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
@@ -1552,6 +1553,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
         }
     }
+
+    if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
+        && !sess.opts.unstable_opts.unstable_options
+    {
+        sess.err(&format!(
+            "`-Csplit-debuginfo={}` is unstable on this platform",
+            sess.split_debuginfo()
+        ));
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index db38ff50c78..9bbee88a894 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,6 +1,6 @@
 use std::{borrow::Cow, env};
 
-use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, TargetOptions};
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
 
 fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
@@ -76,9 +76,15 @@ pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOp
         eh_frame_header: false,
         lld_flavor: LldFlavor::Ld64,
 
+        debuginfo_kind: DebuginfoKind::DwarfDsym,
         // The historical default for macOS targets is to run `dsymutil` which
         // generates a packed version of debuginfo split from the main file.
         split_debuginfo: SplitDebuginfo::Packed,
+        supported_split_debuginfo: Cow::Borrowed(&[
+            SplitDebuginfo::Packed,
+            SplitDebuginfo::Unpacked,
+            SplitDebuginfo::Off,
+        ]),
 
         // This environment variable is pretty magical but is intended for
         // producing deterministic builds. This was first discovered to be used
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index f4fce3b4050..df8e848124a 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -1,4 +1,5 @@
-use crate::spec::{cvs, RelroLevel, TargetOptions};
+use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions};
+use std::borrow::Cow;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -10,6 +11,11 @@ pub fn opts() -> TargetOptions {
         relro_level: RelroLevel::Full,
         has_thread_local: true,
         crt_static_respected: true,
+        supported_split_debuginfo: Cow::Borrowed(&[
+            SplitDebuginfo::Packed,
+            SplitDebuginfo::Unpacked,
+            SplitDebuginfo::Off,
+        ]),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index cf6cb75d49a..8d00129b1b1 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -468,7 +468,57 @@ impl fmt::Display for LinkOutputKind {
 
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
 
-#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
+/// Which kind of debuginfo does the target use?
+///
+/// Useful in determining whether a target supports Split DWARF (a target with
+/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example).
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+pub enum DebuginfoKind {
+    /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`).
+    #[default]
+    Dwarf,
+    /// DWARF debuginfo in dSYM files (such as on Apple platforms).
+    DwarfDsym,
+    /// Program database files (such as on Windows).
+    Pdb,
+}
+
+impl DebuginfoKind {
+    fn as_str(&self) -> &'static str {
+        match self {
+            DebuginfoKind::Dwarf => "dwarf",
+            DebuginfoKind::DwarfDsym => "dwarf-dsym",
+            DebuginfoKind::Pdb => "pdb",
+        }
+    }
+}
+
+impl FromStr for DebuginfoKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "dwarf" => DebuginfoKind::Dwarf,
+            "dwarf-dsym" => DebuginfoKind::DwarfDsym,
+            "pdb" => DebuginfoKind::Pdb,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl ToJson for DebuginfoKind {
+    fn to_json(&self) -> Json {
+        self.as_str().to_json()
+    }
+}
+
+impl fmt::Display for DebuginfoKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
 pub enum SplitDebuginfo {
     /// Split debug-information is disabled, meaning that on supported platforms
     /// you can find all debug information in the executable itself. This is
@@ -476,7 +526,8 @@ pub enum SplitDebuginfo {
     ///
     /// * Windows - not supported
     /// * macOS - don't run `dsymutil`
-    /// * ELF - `.dwarf_*` sections
+    /// * ELF - `.debug_*` sections
+    #[default]
     Off,
 
     /// Split debug-information can be found in a "packed" location separate
@@ -484,7 +535,7 @@ pub enum SplitDebuginfo {
     ///
     /// * Windows - `*.pdb`
     /// * macOS - `*.dSYM` (run `dsymutil`)
-    /// * ELF - `*.dwp` (run `rust-llvm-dwp`)
+    /// * ELF - `*.dwp` (run `thorin`)
     Packed,
 
     /// Split debug-information can be found in individual object files on the
@@ -509,7 +560,7 @@ impl SplitDebuginfo {
 impl FromStr for SplitDebuginfo {
     type Err = ();
 
-    fn from_str(s: &str) -> Result<SplitDebuginfo, ()> {
+    fn from_str(s: &str) -> Result<Self, ()> {
         Ok(match s {
             "off" => SplitDebuginfo::Off,
             "unpacked" => SplitDebuginfo::Unpacked,
@@ -1436,9 +1487,13 @@ pub struct TargetOptions {
     /// thumb and arm interworking.
     pub has_thumb_interworking: bool,
 
+    /// Which kind of debuginfo is used by this target?
+    pub debuginfo_kind: DebuginfoKind,
     /// How to handle split debug information, if at all. Specifying `None` has
     /// target-specific meaning.
     pub split_debuginfo: SplitDebuginfo,
+    /// Which kinds of split debuginfo are supported by the target?
+    pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>,
 
     /// The sanitizers supported by this target
     ///
@@ -1596,7 +1651,10 @@ impl Default for TargetOptions {
             use_ctors_section: false,
             eh_frame_header: true,
             has_thumb_interworking: false,
-            split_debuginfo: SplitDebuginfo::Off,
+            debuginfo_kind: Default::default(),
+            split_debuginfo: Default::default(),
+            // `Off` is supported by default, but targets can remove this manually, e.g. Windows.
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             supported_sanitizers: SanitizerSet::empty(),
             default_adjusted_cabi: None,
             c_enum_min_bits: 32,
@@ -1869,6 +1927,19 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, DebuginfoKind) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
+                    match s.parse::<DebuginfoKind>() {
+                        Ok(level) => base.$key_name = level,
+                        _ => return Some(Err(
+                            format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
+                                  'dwarf-dsym' or 'pdb'.")
+                        )),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, SplitDebuginfo) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@@ -1905,6 +1976,25 @@ impl Target {
                     }
                 }
             } );
+            ($key_name:ident, falliable_list) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.remove(&name).and_then(|j| {
+                    if let Some(v) = j.as_array() {
+                        match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
+                            Ok(l) => { base.$key_name = l },
+                            // FIXME: `falliable_list` can't re-use the `key!` macro for list
+                            // elements and the error messages from that macro, so it has a bad
+                            // generic message instead
+                            Err(_) => return Some(Err(
+                                format!("`{:?}` is not a valid value for `{}`", j, name)
+                            )),
+                        }
+                    } else {
+                        incorrect_type.push(name)
+                    }
+                    Some(Ok(()))
+                }).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(o) = obj.remove(&name) {
@@ -2191,7 +2281,9 @@ impl Target {
         key!(use_ctors_section, bool);
         key!(eh_frame_header, bool);
         key!(has_thumb_interworking, bool);
+        key!(debuginfo_kind, DebuginfoKind)?;
         key!(split_debuginfo, SplitDebuginfo)?;
+        key!(supported_split_debuginfo, falliable_list)?;
         key!(supported_sanitizers, SanitizerSet)?;
         key!(default_adjusted_cabi, Option<Abi>)?;
         key!(c_enum_min_bits, u64);
@@ -2435,7 +2527,9 @@ impl ToJson for Target {
         target_option_val!(use_ctors_section);
         target_option_val!(eh_frame_header);
         target_option_val!(has_thumb_interworking);
+        target_option_val!(debuginfo_kind);
         target_option_val!(split_debuginfo);
+        target_option_val!(supported_split_debuginfo);
         target_option_val!(supported_sanitizers);
         target_option_val!(c_enum_min_bits);
         target_option_val!(generate_arange_section);
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index edb30b72bf6..ec9609a2b26 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -1,4 +1,5 @@
 use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
+use std::borrow::Cow;
 
 pub fn opts() -> TargetOptions {
     // Suppress the verbose logo and authorship debugging output, which would needlessly
@@ -18,6 +19,7 @@ pub fn opts() -> TargetOptions {
         // Currently this is the only supported method of debuginfo on MSVC
         // where `*.pdb` files show up next to the final artifact.
         split_debuginfo: SplitDebuginfo::Packed,
+        supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]),
 
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 0107f7a52c6..81d44a963f1 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -1,5 +1,6 @@
 use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
-use crate::spec::{cvs, LinkerFlavor, TargetOptions};
+use crate::spec::{cvs, DebuginfoKind, LinkerFlavor, SplitDebuginfo, TargetOptions};
+use std::borrow::Cow;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = TargetOptions::link_args(
@@ -86,6 +87,10 @@ pub fn opts() -> TargetOptions {
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
         eh_frame_header: false,
+        // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
+        // output DWO, despite using DWARF, doesn't use ELF..
+        debuginfo_kind: DebuginfoKind::Pdb,
+        supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs
index 21062c337d8..67282c19541 100644
--- a/compiler/rustc_target/src/spec/windows_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, TargetOptions};
+use crate::spec::{cvs, DebuginfoKind, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let base = super::msvc_base::opts();
@@ -28,6 +28,7 @@ pub fn opts() -> TargetOptions {
         // not ever be possible for us to pass this flag.
         no_default_libraries: false,
         has_thread_local: true,
+        debuginfo_kind: DebuginfoKind::Pdb,
 
         ..base
     }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 945299d2dcd..ba732cd7742 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1759,23 +1759,21 @@ impl<'a> Builder<'a> {
             },
         );
 
-        if !target.contains("windows") {
-            let needs_unstable_opts = target.contains("linux")
-                || target.contains("solaris")
-                || target.contains("windows")
-                || target.contains("bsd")
-                || target.contains("dragonfly")
-                || target.contains("illumos");
-
-            if needs_unstable_opts {
-                rustflags.arg("-Zunstable-options");
-            }
-            match self.config.rust_split_debuginfo {
-                SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
-                SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
-                SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
-            };
+        let split_debuginfo_is_stable = target.contains("linux")
+            || target.contains("apple")
+            || (target.contains("msvc")
+                && self.config.rust_split_debuginfo == SplitDebuginfo::Packed)
+            || (target.contains("windows")
+                && self.config.rust_split_debuginfo == SplitDebuginfo::Off);
+
+        if !split_debuginfo_is_stable {
+            rustflags.arg("-Zunstable-options");
         }
+        match self.config.rust_split_debuginfo {
+            SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
+            SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
+            SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
+        };
 
         if self.config.cmd.bless() {
             // Bless `expect!` tests.
diff --git a/src/test/incremental/split_debuginfo_cached.rs b/src/test/incremental/split_debuginfo_cached.rs
index 25c802d5a1d..ba8385f89a7 100644
--- a/src/test/incremental/split_debuginfo_cached.rs
+++ b/src/test/incremental/split_debuginfo_cached.rs
@@ -6,8 +6,8 @@
 // only-x86_64-unknown-linux-gnu
 // revisions:rpass1 rpass2
 
-// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
-// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
+// [rpass1]compile-flags: -g -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
+// [rpass2]compile-flags: -g -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
 
 #![feature(rustc_attrs)]
 // For `rpass2`, nothing has changed so everything should re-used.
diff --git a/src/test/incremental/split_debuginfo_mode.rs b/src/test/incremental/split_debuginfo_mode.rs
index f2533e4146a..edc1a80d30e 100644
--- a/src/test/incremental/split_debuginfo_mode.rs
+++ b/src/test/incremental/split_debuginfo_mode.rs
@@ -6,10 +6,10 @@
 // only-x86_64-unknown-linux-gnu
 // revisions:rpass1 rpass2 rpass3 rpass4
 
-// [rpass1]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
-// [rpass2]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
-// [rpass3]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on
-// [rpass4]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off
+// [rpass1]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
+// [rpass2]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
+// [rpass3]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on
+// [rpass4]compile-flags: -Zquery-dep-graph -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off
 
 #![feature(rustc_attrs)]
 // For rpass2 we change -Csplit-debuginfo and thus expect every CGU to be recompiled
diff --git a/src/test/run-make-fulldeps/split-debuginfo/Makefile b/src/test/run-make-fulldeps/split-debuginfo/Makefile
index 371fb5ffba2..1032f3408f0 100644
--- a/src/test/run-make-fulldeps/split-debuginfo/Makefile
+++ b/src/test/run-make-fulldeps/split-debuginfo/Makefile
@@ -29,14 +29,19 @@ unpacked:
 	[ ! -d $(TMPDIR)/foo.dSYM ]
 else
 ifdef IS_WINDOWS
-# Windows only supports =off
+# Windows only supports =packed
 off:
 packed:
 unpacked:
 else
-# If disabled, don't run dsymutil
+ifeq ($(UNAME),Linux)
+  UNSTABLEOPTS :=
+else
+  UNSTABLEOPTS := -Zunstable-options
+endif
+
 off:
-	$(RUSTC) foo.rs -g -C split-debuginfo=off -Z unstable-options
+	$(RUSTC) foo.rs -g -C $(UNSTABLEOPTS) split-debuginfo=off
 	[ ! -f $(TMPDIR)/*.dwp ]
 	[ ! -f $(TMPDIR)/*.dwo ]
 
@@ -47,12 +52,12 @@ off:
 packed: packed-split packed-single
 
 packed-split:
-	$(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=split
+	$(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=split
 	ls $(TMPDIR)/*.dwp
 	rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
 
 packed-single:
-	$(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=single
+	$(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=packed -Zsplit-dwarf-kind=single
 	ls $(TMPDIR)/*.dwp
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
 	rm -rf $(TMPDIR)/*.dwp
@@ -60,37 +65,37 @@ packed-single:
 packed-remapped: packed-remapped-split packed-remapped-single
 
 packed-remapped-split:
-	$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \
 		-Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 
 packed-remapped-single:
-	$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=packed -C debuginfo=2 \
 		-Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 
 packed-crosscrate: packed-crosscrate-split packed-crosscrate-single
 
 packed-crosscrate-split:
-	$(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+	$(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \
 		-Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
 	ls $(TMPDIR)/*.rlib
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
 	ls $(TMPDIR)/*.dwp && exit 1 || exit 0
-	$(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
-		-Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
+	$(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \
+		-C split-debuginfo=packed -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
 	rm $(TMPDIR)/*.dwo
 	rm $(TMPDIR)/main.dwp
 	rm $(TMPDIR)/$(call BIN,main)
 
 packed-crosscrate-single:
-	$(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+	$(RUSTC) --crate-type lib $(UNSTABLEOPTS) -C split-debuginfo=packed \
 		-Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
 	ls $(TMPDIR)/*.rlib
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
 	ls $(TMPDIR)/*.dwp && exit 1 || exit 0
-	$(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
-		-Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+	$(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options $(UNSTABLEOPTS) \
+		-C split-debuginfo=packed -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
 	rm $(TMPDIR)/main.dwp
 	rm $(TMPDIR)/$(call BIN,main)
@@ -98,23 +103,23 @@ packed-crosscrate-single:
 unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single
 
 unpacked-split:
-	$(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=split
+	$(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=split
 	ls $(TMPDIR)/*.dwp && exit 1 || exit 0
 	ls $(TMPDIR)/*.dwo
 	rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
 
 unpacked-single:
-	$(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=single
+	$(RUSTC) foo.rs -g $(UNSTABLEOPTS) -C split-debuginfo=unpacked -Zsplit-dwarf-kind=single
 	ls $(TMPDIR)/*.dwp && exit 1 || exit 0
 	ls $(TMPDIR)/*.dwo && exit 1 || exit 0
 
 unpacked-remapped-split:
-	$(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
 		-Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 
 unpacked-remapped-single:
-	$(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+	$(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
 		-Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
 	objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 endif
diff --git a/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs b/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs
index 043011b3316..ff764015dc7 100644
--- a/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs
+++ b/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs
@@ -1,6 +1,7 @@
 // build-pass
+// only-linux
 //
-// compile-flags: -g --emit=llvm-ir -Zunstable-options -Csplit-debuginfo=unpacked
+// compile-flags: -g --emit=llvm-ir -Csplit-debuginfo=unpacked
 //
 // Make sure that we don't explode with an error if we don't actually end up emitting any `dwo`s,
 // as would be the case if we don't actually codegen anything.
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 3e9e5a03d5e..3f150843cdd 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2015,11 +2015,14 @@ impl<'test> TestCx<'test> {
             Some(CompareMode::Chalk) => {
                 rustc.args(&["-Zchalk"]);
             }
-            Some(CompareMode::SplitDwarf) => {
+            Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
                 rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
             }
+            Some(CompareMode::SplitDwarf) => {
+                rustc.args(&["-Csplit-debuginfo=unpacked"]);
+            }
             Some(CompareMode::SplitDwarfSingle) => {
-                rustc.args(&["-Csplit-debuginfo=packed", "-Zunstable-options"]);
+                rustc.args(&["-Csplit-debuginfo=packed"]);
             }
             None => {}
         }