diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index a8ddcc9bfac64..59dbea7053447 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -8,6 +8,7 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(let_else)] diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 86f76fdb6a7f6..9d36e37d7b82e 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { // FIXME: The leak sanitizer currently fails the tests, see #88132. base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), "arm64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs index 965b254c2898f..162b091b269ab 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs @@ -2,20 +2,13 @@ // uefi-base module for generic UEFI options. use super::uefi_msvc_base; -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = uefi_msvc_base::opts(); base.max_atomic_width = Some(64); - - let pre_link_args_msvc = vec!["/machine:arm64".into()]; - - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() - .extend(pre_link_args_msvc); + base.add_pre_link_args(LinkerFlavor::Msvc, &["/machine:arm64"]); Target { llvm_target: "aarch64-unknown-windows".into(), diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs index 67df73fa93591..8c2a9bcfde66a 100644 --- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs @@ -1,19 +1,13 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, RelocModel, Target, TargetOptions}; /// A base target for Nintendo 3DS devices using the devkitARM toolchain. /// /// Requires the devkitARM toolchain for 3DS targets on the host system. pub fn target() -> Target { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( + let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ - "-specs=3dsx.specs".into(), - "-mtune=mpcore".into(), - "-mfloat-abi=hard".into(), - "-mtp=soft".into(), - ], + &["-specs=3dsx.specs", "-mtune=mpcore", "-mfloat-abi=hard", "-mtp=soft"], ); Target { diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs index 2afd93fcad807..38c117a495e60 100644 --- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs @@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::android_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]); Target { llvm_target: "armv7-none-linux-android".into(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs index 269bf8b8bcd49..b4cf2c5ee2294 100644 --- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs @@ -2,10 +2,6 @@ use super::{wasm32_unknown_emscripten, LinkerFlavor, Target}; pub fn target() -> Target { let mut target = wasm32_unknown_emscripten::target(); - target.post_link_args.entry(LinkerFlavor::Em).or_default().extend(vec![ - "-sWASM=0".into(), - "--memory-init-file".into(), - "0".into(), - ]); + target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]); target } diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index c288e8b0e9ea3..4fd6c06394daf 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -3,7 +3,8 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; /// A base target for AVR devices using the GNU toolchain. /// /// Requires GNU avr-gcc and avr-binutils on the host system. -pub fn target(target_cpu: &'static str) -> Target { +/// FIXME: Remove the second parameter when const string concatenation is possible. +pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { Target { arch: "avr".into(), data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), @@ -17,10 +18,8 @@ pub fn target(target_cpu: &'static str) -> Target { linker: Some("avr-gcc".into()), executables: true, eh_frame_header: false, - pre_link_args: [(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu).into()])] - .into_iter() - .collect(), - late_link_args: [(LinkerFlavor::Gcc, vec!["-lgcc".into()])].into_iter().collect(), + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &[mmcu]), + late_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &["-lgcc"]), max_atomic_width: Some(0), atomic_cas: false, ..TargetOptions::default() diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs index 6871ca0f78936..6c16b03cc283d 100644 --- a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs +++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs @@ -1,5 +1,5 @@ use crate::spec::Target; pub fn target() -> Target { - super::avr_gnu_base::target("atmega328") + super::avr_gnu_base::target("atmega328", "-mmcu=atmega328") } diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index b64875e32bdd7..b02b70f76eefa 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -1,23 +1,20 @@ -use crate::spec::{ - crt_objects, cvs, LinkArgs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions, -}; +use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Lld(LldFlavor::Ld), - vec![ - "--build-id".into(), - "--hash-style=gnu".into(), - "-z".into(), - "max-page-size=4096".into(), - "-z".into(), - "now".into(), - "-z".into(), - "rodynamic".into(), - "-z".into(), - "separate-loadable-segments".into(), - "--pack-dyn-relocs=relr".into(), + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + "--build-id", + "--hash-style=gnu", + "-z", + "max-page-size=4096", + "-z", + "now", + "-z", + "rodynamic", + "-z", + "separate-loadable-segments", + "--pack-dyn-relocs=relr", ], ); diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs index 7cbd42417e6a0..e43153177f03c 100644 --- a/compiler/rustc_target/src/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -1,10 +1,9 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel}; +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Lld(LldFlavor::Ld), - vec!["--build-id".into(), "--hash-style=gnu".into(), "--Bstatic".into()], + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &["--build-id", "--hash-style=gnu", "--Bstatic"], ); TargetOptions { diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index ad716a6cd5aae..1718bd77b868f 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); base.cpu = "yonah".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs index 554b0f3449945..6318654399c47 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -1,19 +1,16 @@ -use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target}; +use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "pentium4".into(); - base.pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pe".into()]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces base.linker = Some("i686-w64-mingw32-gcc".into()); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("-Wl,--large-address-aware".into()); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs index fb0cb6a69432a..f4ceaa1ca4bb8 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -1,24 +1,22 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - let pre_link_args_msvc = vec![ - // Mark all dynamic libraries and executables as compatible with the larger 4GiB address - // space available to x86 Windows binaries on x86_64. - "/LARGEADDRESSAWARE".into(), - // Ensure the linker will only produce an image if it can also produce a table of - // the image's safe exception handlers. - // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers - "/SAFESEH".into(), - ]; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + base.add_pre_link_args( + LinkerFlavor::Msvc, + &[ + // Mark all dynamic libraries and executables as compatible with the larger 4GiB address + // space available to x86 Windows binaries on x86_64. + "/LARGEADDRESSAWARE", + // Ensure the linker will only produce an image if it can also produce a table of + // the image's safe exception handlers. + // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers + "/SAFESEH", + ], + ); // Workaround for #95429 base.has_thread_local = false; diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index 9f0cb04c65db2..aff284bf2bcf7 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -4,9 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - pre_link_args.push("-m32".into()); - pre_link_args.push("-Wl,-znotext".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-znotext"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index d1af163f1cff3..87aa74e406c97 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index 0998c618f31a9..765803d169280 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index a697f292da0e2..d9492804349b3 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -4,8 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-melf_i386"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index 2807d32820540..8de698b51f087 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index 78462eb63b807..7f25a1a16c179 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -4,8 +4,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-fuse-ld=lld"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs index 75f7a2209c8bd..d52810d2fb08b 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -1,18 +1,15 @@ -use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target}; +use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "pentium4".into(); - base.pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pe".into()]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("-Wl,--large-address-aware".into()); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index d51ed7c1f7aa8..f62404e827936 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs index ef8f90a4da8c4..b0e1b109be1db 100644 --- a/compiler/rustc_target/src/spec/illumos_base.rs +++ b/compiler/rustc_target/src/spec/illumos_base.rs @@ -1,10 +1,9 @@ -use crate::spec::{cvs, FramePointer, LinkArgs, LinkerFlavor, TargetOptions}; +use crate::spec::{cvs, FramePointer, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut late_link_args = LinkArgs::new(); - late_link_args.insert( + let late_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ + &[ // The illumos libc contains a stack unwinding implementation, as // does libgcc_s. The latter implementation includes several // additional symbols that are not always in base libc. To force @@ -15,13 +14,13 @@ pub fn opts() -> TargetOptions { // FIXME: This should be replaced by a more complete and generic // mechanism for controlling the order of library arguments passed // to the linker. - "-lc".into(), + "-lc", // LLVM will insert calls to the stack protector functions // "__stack_chk_fail" and "__stack_chk_guard" into code in native // object files. Some platforms include these symbols directly in // libc, but at least historically these have been provided in // libssp.so on illumos and Solaris systems. - "-lssp".into(), + "-lssp", ], ); diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 03e0934ea5ecc..e3522de6de095 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -1,13 +1,11 @@ use crate::spec::{cvs, Target, TargetOptions}; -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, RelocModel}; +use crate::spec::{LinkerFlavor, LldFlavor, RelocModel}; // The PSP has custom linker requirements. const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld"); pub fn target() -> Target { - let mut pre_link_args = LinkArgs::new(); - pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".into(), "--nmagic".into()]); + let pre_link_args = TargetOptions::link_args(LinkerFlavor::Ld, &["--emit-relocs", "--nmagic"]); Target { llvm_target: "mipsel-sony-psp".into(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index da0589cdd2093..a08603da04095 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1459,6 +1459,44 @@ pub struct TargetOptions { pub supports_stack_protector: bool, } +/// Add arguments for the given flavor and also for its "twin" flavors +/// that have a compatible command line interface. +fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) { + let mut insert = |flavor| { + link_args.entry(flavor).or_default().extend(args.iter().copied().map(Cow::Borrowed)) + }; + insert(flavor); + match flavor { + LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)), + LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)), + LinkerFlavor::Lld(LldFlavor::Wasm) => {} + LinkerFlavor::Lld(lld_flavor) => { + panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor) + } + LinkerFlavor::Gcc + | LinkerFlavor::Em + | LinkerFlavor::L4Bender + | LinkerFlavor::BpfLinker + | LinkerFlavor::PtxLinker => {} + } +} + +impl TargetOptions { + fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs { + let mut link_args = LinkArgs::new(); + add_link_args(&mut link_args, flavor, args); + link_args + } + + fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { + add_link_args(&mut self.pre_link_args, flavor, args); + } + + fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { + add_link_args(&mut self.post_link_args, flavor, args); + } +} + impl Default for TargetOptions { /// Creates a set of "sane defaults" for any target. This is still /// incomplete, and if used for compilation, will certainly not work. diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 00cc9620243da..c4df4b546e329 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -1,14 +1,9 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args_msvc = vec![ - // Suppress the verbose logo and authorship debugging output, which would needlessly - // clog any log files. - "/NOLOGO".into(), - ]; - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone()); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc); + // Suppress the verbose logo and authorship debugging output, which would needlessly + // clog any log files. + let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc, &["/NOLOGO"]); TargetOptions { linker_flavor: LinkerFlavor::Msvc, diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index 595769c4bfa59..803453c4ac411 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs index 24d5d187e1a76..5413c4f33ff61 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); // ld.so in at least RHEL6 on ppc64 has a bug related to BIND_NOW, so only enable partial RELRO diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs index 0f465ccfe776e..159335eb60735 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 491d344aedbcb..b7420d232ca80 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs index b198e667ccc36..a3d1800437139 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs index 09e3936db268d..e18ff3be4485a 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs index 8a947b091cb70..b84943d23a961 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs index c27b84775df4b..516b2de37eaa7 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs @@ -3,12 +3,8 @@ use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); // Extra hint to linker that we are generating secure-PLT code. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("--target=powerpc-unknown-freebsd13.0".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--target=powerpc-unknown-freebsd13.0"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs index 88f61500e3ce3..6686a0bbf04aa 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs index 3ee548750b955..6a250f4b51c90 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs index ce33c787f3339..34200c6790670 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 998225f4dae1c..60661ef9b5d4f 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index 76709cec59103..3f24966e06ec7 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--secure-plt"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs index 7b5d1242c52e3..0f04f41f9e592 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe", "--secure-plt"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs index 718303a4b4d5e..836ab0e37283a 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "v9".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs index 2aaa0ca6df844..4a192df392fa3 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.endian = Endian::Big; base.cpu = "v9".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs index 71d3de0bfd1ba..ea4fafa4b0654 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.endian = Endian::Big; base.cpu = "v9".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mv8plus".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mv8plus"]); Target { llvm_target: "sparc-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs index 79ae54aa6668f..aac09181a74d1 100644 --- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.endian = Endian::Big; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // llvm calls this "v9" base.cpu = "v9".into(); base.vendor = "sun".into(); diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 0865ca7ea7df0..c7c5a23190102 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -1,4 +1,5 @@ use super::super::*; +use std::assert_matches::assert_matches; // Test target self-consistency and JSON encoding/decoding roundtrip. pub(super) fn test_target(target: Target) { @@ -14,35 +15,105 @@ impl Target { assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64"); assert!(self.is_like_windows || !self.is_like_msvc); - // Check that LLD with the given flavor is treated identically to the linker it emulates. - // If your target really needs to deviate from the rules below, except it and document the - // reasons. - assert_eq!( - self.linker_flavor == LinkerFlavor::Msvc - || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link), - self.lld_flavor == LldFlavor::Link, - ); - assert_eq!(self.is_like_msvc, self.lld_flavor == LldFlavor::Link); - for args in &[ + // Check that default linker flavor and lld flavor are compatible + // with some other key properties. + assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64)); + assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link)); + assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm)); + assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender)); + assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em)); + assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker)); + assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker)); + + for args in [ &self.pre_link_args, &self.late_link_args, &self.late_link_args_dynamic, &self.late_link_args_static, &self.post_link_args, ] { + for (&flavor, flavor_args) in args { + assert!(!flavor_args.is_empty()); + // Check that flavors mentioned in link args are compatible with the default flavor. + match (self.linker_flavor, self.lld_flavor) { + ( + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc, + LldFlavor::Ld, + ) => { + assert_matches!( + flavor, + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::Gcc, LldFlavor::Ld64) => { + assert_matches!(flavor, LinkerFlavor::Gcc) + } + (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => { + assert_matches!( + flavor, + LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link) + ) + } + (LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc, LldFlavor::Wasm) => { + assert_matches!( + flavor, + LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::L4Bender, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::L4Bender) + } + (LinkerFlavor::Em, LldFlavor::Wasm) => { + assert_matches!(flavor, LinkerFlavor::Em) + } + (LinkerFlavor::BpfLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::BpfLinker) + } + (LinkerFlavor::PtxLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::PtxLinker) + } + flavors => unreachable!("unexpected flavor combination: {:?}", flavors), + } + + // Check that link args for cc and non-cc versions of flavors are consistent. + let check_noncc = |noncc_flavor| { + if let Some(noncc_args) = args.get(&noncc_flavor) { + for arg in flavor_args { + if let Some(suffix) = arg.strip_prefix("-Wl,") { + assert!(noncc_args.iter().any(|a| a == suffix)); + } + } + } + }; + match self.linker_flavor { + LinkerFlavor::Gcc => match self.lld_flavor { + LldFlavor::Ld => { + check_noncc(LinkerFlavor::Ld); + check_noncc(LinkerFlavor::Lld(LldFlavor::Ld)); + } + LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)), + LldFlavor::Ld64 | LldFlavor::Link => {} + }, + _ => {} + } + } + + // Check that link args for lld and non-lld versions of flavors are consistent. + assert_eq!(args.get(&LinkerFlavor::Ld), args.get(&LinkerFlavor::Lld(LldFlavor::Ld))); assert_eq!( args.get(&LinkerFlavor::Msvc), args.get(&LinkerFlavor::Lld(LldFlavor::Link)), ); - if args.contains_key(&LinkerFlavor::Msvc) { - assert_eq!(self.lld_flavor, LldFlavor::Link); - } } + assert!( (self.pre_link_objects_fallback.is_empty() && self.post_link_objects_fallback.is_empty()) || self.crt_objects_fallback.is_some() ); + + // If your target really needs to deviate from the rules below, + // except it and document the reasons. // Keep the default "unknown" vendor instead. assert_ne!(self.vendor, ""); if !self.can_use_os_unknown() { diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs index f6cbbd38cf4aa..4d09d3a4d106f 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); @@ -9,12 +9,7 @@ pub fn target() -> Target { // should be smart enough to insert branch islands only // where necessary, but this is not the observed behavior. // Disabling the LBR optimization works around the issue. - let pre_link_args_msvc = "/OPT:NOLBR"; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().push(pre_link_args_msvc.into()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .push(pre_link_args_msvc.into()); + base.add_pre_link_args(LinkerFlavor::Msvc, &["/OPT:NOLBR"]); Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs index 9a3e8b5c5f8f2..4cad9e1837010 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs @@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::android_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]); Target { llvm_target: "armv7-none-linux-android".into(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index bc7244b3a4551..aee8eb2e31c7a 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -14,27 +14,25 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, Target pub fn opts() -> TargetOptions { let mut base = super::msvc_base::opts(); - let pre_link_args_msvc = vec![ - // Non-standard subsystems have no default entry-point in PE+ files. We have to define - // one. "efi_main" seems to be a common choice amongst other implementations and the - // spec. - "/entry:efi_main".into(), - // COFF images have a "Subsystem" field in their header, which defines what kind of - // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION, - // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION, - // which is very likely the most common option. Individual projects can override this - // with custom linker flags. - // The subsystem-type only has minor effects on the application. It defines the memory - // regions the application is loaded into (runtime-drivers need to be put into - // reserved areas), as well as whether a return from the entry-point is treated as - // exit (default for applications). - "/subsystem:efi_application".into(), - ]; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + base.add_pre_link_args( + LinkerFlavor::Msvc, + &[ + // Non-standard subsystems have no default entry-point in PE+ files. We have to define + // one. "efi_main" seems to be a common choice amongst other implementations and the + // spec. + "/entry:efi_main", + // COFF images have a "Subsystem" field in their header, which defines what kind of + // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION, + // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION, + // which is very likely the most common option. Individual projects can override this + // with custom linker flags. + // The subsystem-type only has minor effects on the application. It defines the memory + // regions the application is loaded into (runtime-drivers need to be put into + // reserved areas), as well as whether a return from the entry-point is treated as + // exit (default for applications). + "/subsystem:efi_application", + ], + ); TargetOptions { os: "uefi".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 1b94c59b55f09..c7e7d22108656 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -2,21 +2,11 @@ use super::{cvs, wasm_base}; use super::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; pub fn target() -> Target { - let mut options = wasm_base::options(); - - let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - - // Rust really needs a way for users to specify exports and imports in - // the source code. --export-dynamic isn't the right tool for this job, - // however it does have the side effect of automatically exporting a lot - // of symbols, which approximates what people want when compiling for - // wasm32-unknown-unknown expect, so use it for now. - clang_args.push("--export-dynamic".into()); - - let mut post_link_args = LinkArgs::new(); - post_link_args.insert( + // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. + let pre_link_args = LinkArgs::new(); + let post_link_args = TargetOptions::link_args( LinkerFlavor::Em, - vec!["-sABORTING_MALLOC=0".into(), "-Wl,--fatal-warnings".into()], + &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], ); let opts = TargetOptions { @@ -26,12 +16,13 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".into(), linker: None, + pre_link_args, + post_link_args, relocation_model: RelocModel::Pic, panic_strategy: PanicStrategy::Unwind, no_default_libraries: false, - post_link_args, families: cvs!["unix", "wasm"], - ..options + ..wasm_base::options() }; Target { llvm_target: "wasm32-unknown-emscripten".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 214b5fce5a6b0..4e2927dd913c2 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -29,27 +29,30 @@ pub fn target() -> Target { // code on this target due to this ABI mismatch. options.default_adjusted_cabi = Some(Abi::Wasm); - let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - - // Make sure clang uses LLD as its linker and is configured appropriately - // otherwise - clang_args.push("--target=wasm32-unknown-unknown".into()); - - // For now this target just never has an entry symbol no matter the output - // type, so unconditionally pass this. - clang_args.push("-Wl,--no-entry".into()); - - // Rust really needs a way for users to specify exports and imports in - // the source code. --export-dynamic isn't the right tool for this job, - // however it does have the side effect of automatically exporting a lot - // of symbols, which approximates what people want when compiling for - // wasm32-unknown-unknown expect, so use it for now. - clang_args.push("-Wl,--export-dynamic".into()); - - // Add the flags to wasm-ld's args too. - let lld_args = options.pre_link_args.entry(LinkerFlavor::Lld(LldFlavor::Wasm)).or_default(); - lld_args.push("--no-entry".into()); - lld_args.push("--export-dynamic".into()); + options.add_pre_link_args( + LinkerFlavor::Lld(LldFlavor::Wasm), + &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + // Rust really needs a way for users to specify exports and imports in + // the source code. --export-dynamic isn't the right tool for this job, + // however it does have the side effect of automatically exporting a lot + // of symbols, which approximates what people want when compiling for + // wasm32-unknown-unknown expect, so use it for now. + "--export-dynamic", + ], + ); + options.add_pre_link_args( + LinkerFlavor::Gcc, + &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm32-unknown-unknown", + "-Wl,--no-entry", + "-Wl,--export-dynamic", + ], + ); Target { llvm_target: "wasm32-unknown-unknown".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 10eb78e4e25b7..280457d68b99e 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -80,11 +80,7 @@ pub fn target() -> Target { options.os = "wasi".into(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); - options - .pre_link_args - .entry(LinkerFlavor::Gcc) - .or_insert(Vec::new()) - .push("--target=wasm32-wasi".into()); + options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]); options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback(); options.post_link_objects_fallback = crt_objects::post_wasi_fallback(); diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs index 6826c0ac62b3a..5211f7707fbb2 100644 --- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs @@ -14,19 +14,25 @@ pub fn target() -> Target { let mut options = wasm_base::options(); options.os = "unknown".into(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); - let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); - // Make sure clang uses LLD as its linker and is configured appropriately - // otherwise - clang_args.push("--target=wasm64-unknown-unknown".into()); - - // For now this target just never has an entry symbol no matter the output - // type, so unconditionally pass this. - clang_args.push("-Wl,--no-entry".into()); - - let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap(); - lld_args.push("--no-entry".into()); - lld_args.push("-mwasm64".into()); + options.add_pre_link_args( + LinkerFlavor::Lld(LldFlavor::Wasm), + &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + "-mwasm64", + ], + ); + options.add_pre_link_args( + LinkerFlavor::Gcc, + &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm64-unknown-unknown", + "-Wl,--no-entry", + ], + ); // Any engine that implements wasm64 will surely implement the rest of these // features since they were all merged into the official spec by the time diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index de7b7374af314..5736402ae14ef 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -1,63 +1,56 @@ use super::crt_objects::CrtObjectsFallback; use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; -use std::collections::BTreeMap; pub fn options() -> TargetOptions { - let mut lld_args = Vec::new(); - let mut clang_args = Vec::new(); - let mut arg = |arg: &'static str| { - lld_args.push(arg.into()); - clang_args.push(format!("-Wl,{}", arg).into()); - }; - - // By default LLD only gives us one page of stack (64k) which is a - // little small. Default to a larger stack closer to other PC platforms - // (1MB) and users can always inject their own link-args to override this. - arg("-z"); - arg("stack-size=1048576"); - - // By default LLD's memory layout is: - // - // 1. First, a blank page - // 2. Next, all static data - // 3. Finally, the main stack (which grows down) - // - // This has the unfortunate consequence that on stack overflows you - // corrupt static data and can cause some exceedingly weird bugs. To - // help detect this a little sooner we instead request that the stack is - // placed before static data. - // - // This means that we'll generate slightly larger binaries as references - // to static data will take more bytes in the ULEB128 encoding, but - // stack overflow will be guaranteed to trap as it underflows instead of - // corrupting static data. - arg("--stack-first"); - - // FIXME we probably shouldn't pass this but instead pass an explicit list - // of symbols we'll allow to be undefined. We don't currently have a - // mechanism of knowing, however, which symbols are intended to be imported - // from the environment and which are intended to be imported from other - // objects linked elsewhere. This is a coarse approximation but is sure to - // hide some bugs and frustrate someone at some point, so we should ideally - // work towards a world where we can explicitly list symbols that are - // supposed to be imported and have all other symbols generate errors if - // they remain undefined. - arg("--allow-undefined"); - - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - arg("--fatal-warnings"); - - // LLD only implements C++-like demangling, which doesn't match our own - // mangling scheme. Tell LLD to not demangle anything and leave it up to - // us to demangle these symbols later. Currently rustc does not perform - // further demangling, but tools like twiggy and wasm-bindgen are intended - // to do so. - arg("--no-demangle"); - - let mut pre_link_args = BTreeMap::new(); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); - pre_link_args.insert(LinkerFlavor::Gcc, clang_args); + macro_rules! args { + ($prefix:literal) => { + &[ + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. + concat!($prefix, "-z"), + concat!($prefix, "stack-size=1048576"), + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + concat!($prefix, "--stack-first"), + // FIXME we probably shouldn't pass this but instead pass an explicit list + // of symbols we'll allow to be undefined. We don't currently have a + // mechanism of knowing, however, which symbols are intended to be imported + // from the environment and which are intended to be imported from other + // objects linked elsewhere. This is a coarse approximation but is sure to + // hide some bugs and frustrate someone at some point, so we should ideally + // work towards a world where we can explicitly list symbols that are + // supposed to be imported and have all other symbols generate errors if + // they remain undefined. + concat!($prefix, "--allow-undefined"), + // Rust code should never have warnings, and warnings are often + // indicative of bugs, let's prevent them. + concat!($prefix, "--fatal-warnings"), + // LLD only implements C++-like demangling, which doesn't match our own + // mangling scheme. Tell LLD to not demangle anything and leave it up to + // us to demangle these symbols later. Currently rustc does not perform + // further demangling, but tools like twiggy and wasm-bindgen are intended + // to do so. + concat!($prefix, "--no-demangle"), + ] + }; + } + + let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Lld(LldFlavor::Wasm), args!("")); + super::add_link_args(&mut pre_link_args, LinkerFlavor::Gcc, args!("-Wl,")); TargetOptions { is_like_wasm: true, diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index d11f1f7d3f856..a0480f386f74e 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -1,31 +1,35 @@ use crate::spec::crt_objects::{self, CrtObjectsFallback}; -use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( + let mut pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + // Enable ASLR + "--dynamicbase", + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "--disable-auto-image-base", + ], + ); + super::add_link_args( + &mut pre_link_args, LinkerFlavor::Gcc, - vec![ + &[ // Tell GCC to avoid linker plugins, because we are not bundling // them with Windows installer, and Rust does its own LTO anyways. - "-fno-use-linker-plugin".into(), - // Enable ASLR - "-Wl,--dynamicbase".into(), - // ASLR will rebase it anyway so leaving that option enabled only leads to confusion - "-Wl,--disable-auto-image-base".into(), + "-fno-use-linker-plugin", + "-Wl,--dynamicbase", + "-Wl,--disable-auto-image-base", ], ); - let mut late_link_args = LinkArgs::new(); - let mut late_link_args_dynamic = LinkArgs::new(); - let mut late_link_args_static = LinkArgs::new(); // Order of `late_link_args*` was found through trial and error to work with various // mingw-w64 versions (not tested on the CI). It's expected to change from time to time. - let mingw_libs = vec![ - "-lmsvcrt".into(), - "-lmingwex".into(), - "-lmingw32".into(), - "-lgcc".into(), // alas, mingw* libraries above depend on libgcc + let mingw_libs = &[ + "-lmsvcrt", + "-lmingwex", + "-lmingw32", + "-lgcc", // alas, mingw* libraries above depend on libgcc // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example @@ -33,31 +37,27 @@ pub fn opts() -> TargetOptions { // The library is purposely listed twice to fix that. // // See https://github.com/rust-lang/rust/pull/47483 for some more details. - "-lmsvcrt".into(), - "-luser32".into(), - "-lkernel32".into(), - ]; - late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); - let dynamic_unwind_libs = vec![ - // If any of our crates are dynamically linked then we need to use - // the shared libgcc_s-dw2-1.dll. This is required to support - // unwinding across DLL boundaries. - "-lgcc_s".into(), - ]; - late_link_args_dynamic.insert(LinkerFlavor::Gcc, dynamic_unwind_libs.clone()); - late_link_args_dynamic.insert(LinkerFlavor::Lld(LldFlavor::Ld), dynamic_unwind_libs); - let static_unwind_libs = vec![ - // If all of our crates are statically linked then we can get away - // with statically linking the libgcc unwinding code. This allows - // binaries to be redistributed without the libgcc_s-dw2-1.dll - // dependency, but unfortunately break unwinding across DLL - // boundaries when unwinding across FFI boundaries. - "-lgcc_eh".into(), - "-l:libpthread.a".into(), + "-lmsvcrt", + "-luser32", + "-lkernel32", ]; - late_link_args_static.insert(LinkerFlavor::Gcc, static_unwind_libs.clone()); - late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs); + let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs); + super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs); + // If any of our crates are dynamically linked then we need to use + // the shared libgcc_s-dw2-1.dll. This is required to support + // unwinding across DLL boundaries. + let dynamic_unwind_libs = &["-lgcc_s"]; + let mut late_link_args_dynamic = + TargetOptions::link_args(LinkerFlavor::Ld, dynamic_unwind_libs); + super::add_link_args(&mut late_link_args_dynamic, LinkerFlavor::Gcc, dynamic_unwind_libs); + // If all of our crates are statically linked then we can get away + // with statically linking the libgcc unwinding code. This allows + // binaries to be redistributed without the libgcc_s-dw2-1.dll + // dependency, but unfortunately break unwinding across DLL + // boundaries when unwinding across FFI boundaries. + let static_unwind_libs = &["-lgcc_eh", "-l:libpthread.a"]; + let mut late_link_args_static = TargetOptions::link_args(LinkerFlavor::Ld, static_unwind_libs); + super::add_link_args(&mut late_link_args_static, LinkerFlavor::Gcc, static_unwind_libs); TargetOptions { os: "windows".into(), diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs index 9f9f8be87184e..30f995007a9c6 100644 --- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -1,28 +1,17 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args = LinkArgs::from([( + // We cannot use `-nodefaultlibs` because compiler-rt has to be passed + // as a path since it's not added to linker search path by the default. + // There were attemts to make it behave like libgcc (so one can just use -l) + // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 + let pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]); + // Order of `late_link_args*` does not matter with LLD. + let late_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ - // We cannot use `-nodefaultlibs` because compiler-rt has to be passed - // as a path since it's not added to linker search path by the default. - // There were attemts to make it behave like libgcc (so one can just use -l) - // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 - "-nolibc".into(), - "--unwindlib=none".into(), - ], - )]); - let late_link_args = LinkArgs::from([( - LinkerFlavor::Gcc, - // Order of `late_link_args*` does not matter with LLD. - vec![ - "-lmingw32".into(), - "-lmingwex".into(), - "-lmsvcrt".into(), - "-lkernel32".into(), - "-luser32".into(), - ], - )]); + &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"], + ); TargetOptions { os: "windows".into(), diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index 119683917768b..334dec43ef7e0 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -1,28 +1,25 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let base = super::windows_gnu_base::opts(); // FIXME: This should be updated for the exception machinery changes from #67502 // and inherit from `windows_gnu_base`, at least partially. - let mut late_link_args = LinkArgs::new(); + let mingw_libs = &[ + "-lwinstorecompat", + "-lruntimeobject", + "-lsynchronization", + "-lvcruntime140_app", + "-lucrt", + "-lwindowsapp", + "-lmingwex", + "-lmingw32", + ]; + let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs); + super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs); + // Reset the flags back to empty until the FIXME above is addressed. let late_link_args_dynamic = LinkArgs::new(); let late_link_args_static = LinkArgs::new(); - let mingw_libs = vec![ - //"-lwinstorecompat".into(), - //"-lmingwex".into(), - //"-lwinstorecompat".into(), - "-lwinstorecompat".into(), - "-lruntimeobject".into(), - "-lsynchronization".into(), - "-lvcruntime140_app".into(), - "-lucrt".into(), - "-lwindowsapp".into(), - "-lmingwex".into(), - "-lmingw32".into(), - ]; - late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); TargetOptions { abi: "uwp".into(), diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs index d6b065b529a56..f2573fc2d2115 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs @@ -1,16 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let mut opts = super::windows_msvc_base::opts(); opts.abi = "uwp".into(); opts.vendor = "uwp".into(); - let pre_link_args_msvc = vec!["/APPCONTAINER".into(), "mincore.lib".into()]; - opts.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - opts.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + opts.add_pre_link_args(LinkerFlavor::Msvc, &["/APPCONTAINER", "mincore.lib"]); opts } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 51d14f0403a55..dbd26899c1899 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.cpu = "core2".into(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.frame_pointer = FramePointer::Always; - base.pre_link_args - .insert(LinkerFlavor::Gcc, vec!["-m64".into(), "-arch".into(), "x86_64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index 47c70513faf88..4348d92457945 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -1,41 +1,44 @@ -use std::{borrow::Cow, iter}; +use std::borrow::Cow; use crate::spec::cvs; use super::{LinkerFlavor, LldFlavor, Target, TargetOptions}; pub fn target() -> Target { - const PRE_LINK_ARGS: &[&str] = &[ - "-e", - "elf_entry", - "-Bstatic", - "--gc-sections", - "-z", - "text", - "-z", - "norelro", - "--no-undefined", - "--error-unresolved-symbols", - "--no-undefined-version", - "-Bsymbolic", - "--export-dynamic", - // The following symbols are needed by libunwind, which is linked after - // libstd. Make sure they're included in the link. - "-u", - "__rust_abort", - "-u", - "__rust_c_alloc", - "-u", - "__rust_c_dealloc", - "-u", - "__rust_print_err", - "-u", - "__rust_rwlock_rdlock", - "-u", - "__rust_rwlock_unlock", - "-u", - "__rust_rwlock_wrlock", - ]; + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + "-e", + "elf_entry", + "-Bstatic", + "--gc-sections", + "-z", + "text", + "-z", + "norelro", + "--no-undefined", + "--error-unresolved-symbols", + "--no-undefined-version", + "-Bsymbolic", + "--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-u", + "__rust_abort", + "-u", + "__rust_c_alloc", + "-u", + "__rust_c_dealloc", + "-u", + "__rust_print_err", + "-u", + "__rust_rwlock_rdlock", + "-u", + "__rust_rwlock_unlock", + "-u", + "__rust_rwlock_wrlock", + ], + ); const EXPORT_SYMBOLS: &[&str] = &[ "sgx_entry", @@ -66,11 +69,7 @@ pub fn target() -> Target { features: "+rdrnd,+rdseed,+lvi-cfi,+lvi-load-hardening".into(), llvm_args: cvs!["--x86-experimental-lvi-inline-asm-hardening"], position_independent_executables: true, - pre_link_args: iter::once(( - LinkerFlavor::Lld(LldFlavor::Ld), - PRE_LINK_ARGS.iter().cloned().map(Cow::from).collect(), - )) - .collect(), + pre_link_args, override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()), relax_elf_relocations: true, ..Default::default() diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 049cab0d554ec..6d19cf265744e 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { // https://developer.android.com/ndk/guides/abis.html#86-64 base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index 2a697daeb28f8..0550b221fd9ea 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.cpu = "x86-64".into(); base.vendor = "pc".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index 0fa43481c9bbb..59a8cffca480a 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -1,14 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); // Use high-entropy 64 bit address space for ASLR - gcc_pre_link_args.push("-Wl,--high-entropy-va".into()); - base.pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pep".into()]); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-gcc".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs index b5ff63e0532fd..d3909b3895e52 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnullvm_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index a02018266fbb2..cbe87589a702d 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.cpu = "x86-64".into(); base.vendor = "sun".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 1f2b998a7ba5f..746f647817801 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index c9aedd6ea82f7..b30784ed69291 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.supported_sanitizers = diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index aebbd18c66a4f..d6d0336298281 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; // This option is required to build executables on Haiku x86_64 diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index 9529fa9640dfa..9f19c3a2b2a91 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, Target}; pub fn target() -> Target { let mut base = super::illumos_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into(), "-std=c99".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-std=c99"]); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index e525cfdde14fb..956be0353fa39 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.static_position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 863b41633e247..140882747c282 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.abi = "x32".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mx32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.has_thread_local = false; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index 8678f06e2cb56..87e7784d1f9e9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.static_position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index a7115dace1c08..d3a67619aa86e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs index 0db88d64ac072..593345a5f1d8c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".into(); base.code_model = Some(CodeModel::Kernel); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); Target { // FIXME: Some dispute, the linux-on-clang folks think this should use diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 11e9cc4abc0c0..f50c6bceec942 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index af8b9673c3063..668ae90541711 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index a94bbbf6edeb9..76d2013cf7fdc 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -1,14 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); // Use high-entropy 64 bit address space for ASLR - gcc_pre_link_args.push("-Wl,--high-entropy-va".into()); - base.pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pep".into()]); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 16d29753e7dc4..1298974952f94 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.disable_redzone = true;