diff --git a/compiler/rustc_target/src/spec/base/thumb.rs b/compiler/rustc_target/src/spec/base/arm_none.rs similarity index 54% rename from compiler/rustc_target/src/spec/base/thumb.rs rename to compiler/rustc_target/src/spec/base/arm_none.rs index 03ec679038c08..feb69bdd26cd9 100644 --- a/compiler/rustc_target/src/spec/base/thumb.rs +++ b/compiler/rustc_target/src/spec/base/arm_none.rs @@ -1,31 +1,4 @@ -// These `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in -// microcontrollers. Namely, all these processors: -// -// - Cortex-M0 -// - Cortex-M0+ -// - Cortex-M1 -// - Cortex-M3 -// - Cortex-M4(F) -// - Cortex-M7(F) -// - Cortex-M23 -// - Cortex-M33 -// -// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`, -// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost -// nonexistent from the POV of codegen so it doesn't make sense to have separate targets for them. -// And if differences exist between two processors under the same target, rustc flags can be used to -// optimize for one processor or the other. -// -// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes -// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags -// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to -// differentiate one processor from the other. -// -// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set, -// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM -// triples use thumb instead of arm. We follow suit because having thumb in the name let us -// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of -// build scripts / gcc flags. +// These are the baseline settings for 32-bit bare-metal Arm targets using the EABI or EABIHF ABI. use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions}; diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index ca1c9649ee4d7..9e7ff620fea43 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -1,6 +1,7 @@ pub(crate) mod aix; pub(crate) mod android; pub mod apple; +pub(crate) mod arm_none; pub(crate) mod avr; pub(crate) mod bpf; pub(crate) mod cygwin; @@ -31,7 +32,6 @@ pub(crate) mod redox; pub(crate) mod solaris; pub(crate) mod solid; pub(crate) mod teeos; -pub(crate) mod thumb; pub(crate) mod uefi_msvc; pub(crate) mod unikraft_linux_musl; pub(crate) mod vxworks; diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index 129b639c5248d..fc66a2fa8f9ef 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -9,10 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{ - Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -25,35 +22,16 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), - linker: Some("rust-lld".into()), asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], - // Force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - main_needs_argc_argv: false, + features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, - relocation_model: RelocModel::Static, - panic_strategy: PanicStrategy::Abort, - // From thumb_base, rust-lang/rust#44993. - emit_debug_gdb_scripts: false, - // From thumb_base, GCC gives enums a minimum of 8 bits on no-os targets. - c_enum_min_bits: Some(8), - ..Default::default() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index 7cd571b914796..8089e9a7a0640 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -1,8 +1,6 @@ //! Targets the ARMv5TE, with code as `a32` code by default. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,36 +13,16 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), - options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv5TE - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], - // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - frame_pointer: FramePointer::MayOmit, - main_needs_argc_argv: false, - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, - - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 0498c55e98271..50eccbed3ac10 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -9,10 +9,7 @@ //! The default link script is very likely wrong, so you should use //! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -25,44 +22,16 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv4T - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], - - // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - - panic_strategy: PanicStrategy::Abort, - relocation_model: RelocModel::Static, - // suggested from thumb_base, rust-lang/rust#44993. - emit_debug_gdb_scripts: false, - frame_pointer: FramePointer::MayOmit, - - main_needs_argc_argv: false, - - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, - - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index a07e9127a36e0..6acb03e3b296b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -1,8 +1,6 @@ //! Targets the ARMv5TE, with code as `t32` code by default. -use crate::spec::{ - Abi, Arch, FloatAbi, FramePointer, Target, TargetMetadata, TargetOptions, base, cvs, -}; +use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -15,36 +13,16 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, arch: Arch::Arm, - /* Data layout args are '-' separated: - * little endian - * stack is 64-bit aligned (EABI) - * pointers are 32-bit - * i64 must be 64-bit aligned (EABI) - * mangle names with ELF style - * native integers are 32-bit - * All other elements are default - */ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), - options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - // extra args passed to the external assembler (assuming `arm-none-eabi-as`): - // * activate t32/a32 interworking - // * use arch ARMv5TE - // * use little-endian asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], - // minimum extra features, these cannot be disabled via -C - // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. - // The resulting atomics are ABI incompatible with atomics backed by libatomic. - features: "+soft-float,+strict-align,+atomics-32".into(), - frame_pointer: FramePointer::MayOmit, - main_needs_argc_argv: false, - // don't have atomic compare-and-swap + features: "+soft-float,+strict-align".into(), atomic_cas: false, + max_atomic_width: Some(0), has_thumb_interworking: true, - - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs index 836b2ff63a16a..cc81cb92be6bc 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs @@ -26,7 +26,7 @@ pub(crate) fn target() -> Target { // There are no atomic CAS instructions available in the instruction set of the ARMv6-M // architecture atomic_cas: false, - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs index fa0154d65d683..8b58d2e16eec8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_nuttx_eabi.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { // The ARMv6-M doesn't support hardware atomic operations, use atomic builtins instead. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs index 7c1adc932626a..17d25a67acbd1 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target { // Cortex-A7/A8/A9 with software floating point features: "+soft-float,-neon".into(), max_atomic_width: Some(64), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs index 0e6d5b1f2ea9f..a4e17004e7bfa 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs @@ -31,7 +31,7 @@ pub(crate) fn target() -> Target { // and NEON SIMD instructions features: "+vfp3,+neon".into(), max_atomic_width: Some(64), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs index 9e0f09b45191c..6e6975c01f815 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs @@ -28,7 +28,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index acc31cc42d4a7..6a7fe14a26dff 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -36,7 +36,7 @@ pub(crate) fn target() -> Target { // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension features: "+vfp4d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs index 796206d4ffee4..10173273b5d8d 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabi.rs @@ -30,7 +30,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs index f85aef1ab5a6f..1f24155a7dab1 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_nuttx_eabihf.rs @@ -38,7 +38,7 @@ pub(crate) fn target() -> Target { // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension features: "+vfp4d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs index 8c5807b1a907f..8851f7b634374 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs index 3d3d48748a9cf..9f0261c69b3ff 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_nuttx_eabi.rs @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs index 298bad565e481..7426eb9bd5e2c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { // with +strict-align. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs index 18bafc72553dc..a74719ba2f0c3 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_nuttx_eabi.rs @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { // with +strict-align. features: "+strict-align".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs index 90d7df75d44bd..540d4bdee07ce 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index debdb47d507b2..2287cce395aa8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { // and 16 D registers. features: "+fp-armv8d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs index f5039f13bc099..ec107292d5290 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabi.rs @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs index 77d23a255278f..9ff924b6386b7 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_nuttx_eabihf.rs @@ -27,7 +27,7 @@ pub(crate) fn target() -> Target { // and 16 D registers. features: "+fp-armv8d16sp".into(), max_atomic_width: Some(32), - ..base::thumb::opts() + ..base::arm_none::opts() }, } } diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 091376d5d685b..66ea22e75247c 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -104,9 +104,14 @@ where { type Item = (K, V); - /// If two keys are equal, returns the key-value pair from the right source. + /// If two keys are equal, returns the key from the left and the value from the right. fn next(&mut self) -> Option<(K, V)> { let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); - b_next.or(a_next) + match (a_next, b_next) { + (Some((a_k, _)), Some((_, b_v))) => Some((a_k, b_v)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + } } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 71ed8ca1468a7..79f355a8d9272 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1181,6 +1181,10 @@ impl BTreeMap { /// /// If a key from `other` is already present in `self`, the respective /// value from `self` will be overwritten with the respective value from `other`. + /// Similar to [`insert`], though, the key is not overwritten, + /// which matters for types that can be `==` without being identical. + /// + /// [`insert`]: BTreeMap::insert /// /// # Examples /// diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 79879d31d3dfd..a61a2da172d1e 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -11,7 +11,7 @@ use crate::fmt::Debug; use crate::rc::Rc; use crate::string::{String, ToString}; use crate::testing::crash_test::{CrashTestDummy, Panic}; -use crate::testing::ord_chaos::{Cyclic3, Governed, Governor}; +use crate::testing::ord_chaos::{Cyclic3, Governed, Governor, IdBased}; use crate::testing::rng::DeterministicRng; // Minimum number of elements to insert, to guarantee a tree with 2 levels, @@ -2137,9 +2137,9 @@ fn test_append_drop_leak() { let mut left = BTreeMap::new(); let mut right = BTreeMap::new(); left.insert(a.spawn(Panic::Never), ()); - left.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append + left.insert(b.spawn(Panic::Never), ()); left.insert(c.spawn(Panic::Never), ()); - right.insert(b.spawn(Panic::Never), ()); + right.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append right.insert(c.spawn(Panic::Never), ()); catch_unwind(move || left.append(&mut right)).unwrap_err(); @@ -2587,3 +2587,31 @@ fn cursor_peek_prev_agrees_with_cursor_mut() { let prev = cursor.peek_prev(); assert_matches!(prev, Some((&3, _))); } + +#[test] +fn test_id_based_insert() { + let mut lhs = BTreeMap::new(); + let mut rhs = BTreeMap::new(); + + lhs.insert(IdBased { id: 0, name: "lhs_k".to_string() }, "lhs_v".to_string()); + rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "rhs_v".to_string()); + + for (k, v) in rhs.into_iter() { + lhs.insert(k, v); + } + + assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); +} + +#[test] +fn test_id_based_append() { + let mut lhs = BTreeMap::new(); + let mut rhs = BTreeMap::new(); + + lhs.insert(IdBased { id: 0, name: "lhs_k".to_string() }, "lhs_v".to_string()); + rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "rhs_v".to_string()); + + lhs.append(&mut rhs); + + assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); +} diff --git a/library/alloctests/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs index 55e1ae5e3deaa..f90ba1c69921e 100644 --- a/library/alloctests/testing/ord_chaos.rs +++ b/library/alloctests/testing/ord_chaos.rs @@ -2,6 +2,8 @@ use std::cell::Cell; use std::cmp::Ordering::{self, *}; use std::ptr; +use crate::string::String; + // Minimal type with an `Ord` implementation violating transitivity. #[derive(Debug)] pub(crate) enum Cyclic3 { @@ -79,3 +81,31 @@ impl PartialEq for Governed<'_, T> { } impl Eq for Governed<'_, T> {} + +// Comparison based only on the ID, the name is ignored. +#[derive(Debug)] +pub(crate) struct IdBased { + pub id: u32, + #[allow(dead_code)] + pub name: String, +} + +impl PartialEq for IdBased { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for IdBased {} + +impl PartialOrd for IdBased { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for IdBased { + fn cmp(&self, other: &Self) -> Ordering { + self.id.cmp(&other.id) + } +} diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0c5552a0b81cc..0601019abbd5c 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -130,16 +130,18 @@ //! //! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or //! `AtomicI64` types. -//! * ARM platforms like `armv5te` that aren't for Linux only provide `load` -//! and `store` operations, and do not support Compare and Swap (CAS) -//! operations, such as `swap`, `fetch_add`, etc. Additionally on Linux, -//! these CAS operations are implemented via [operating system support], which -//! may come with a performance penalty. -//! * ARM targets with `thumbv6m` only provide `load` and `store` operations, -//! and do not support Compare and Swap (CAS) operations, such as `swap`, -//! `fetch_add`, etc. +//! * Legacy ARM platforms like ARMv4T and ARMv5TE have very limited hardware +//! support for atomics. The bare-metal targets disable this module +//! entirely, but the Linux targets [use the kernel] to assist (which comes +//! with a performance penalty). It's not until ARMv6K onwards that ARM CPUs +//! have support for load/store and Compare and Swap (CAS) atomics in hardware. +//! * ARMv6-M and ARMv8-M baseline targets (`thumbv6m-*` and +//! `thumbv8m.base-*`) only provide `load` and `store` operations, and do +//! not support Compare and Swap (CAS) operations, such as `swap`, +//! `fetch_add`, etc. Full CAS support is available on ARMv7-M and ARMv8-M +//! Mainline (`thumbv7m-*`, `thumbv7em*` and `thumbv8m.main-*`). //! -//! [operating system support]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt +//! [use the kernel]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt //! //! Note that future platforms may be added that also do not have support for //! some atomic operations. Maximally portable code will want to be careful diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0efe0cbbc80f0..40149ee09427c 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -347,14 +347,14 @@ fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder let mut rustc_dlls = vec![]; // windows-gnu and windows-gnullvm require different runtime libs - if target.ends_with("windows-gnu") { + if target.is_windows_gnu() { rustc_dlls.push("libwinpthread-1.dll"); if target.starts_with("i686-") { rustc_dlls.push("libgcc_s_dw2-1.dll"); } else { rustc_dlls.push("libgcc_s_seh-1.dll"); } - } else if target.ends_with("windows-gnullvm") { + } else if target.is_windows_gnullvm() { rustc_dlls.push("libunwind.dll"); } else { panic!("Vendoring of runtime DLLs for `{target}` is not supported`"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index a591be05291fa..db2a76c4a2dff 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -210,7 +210,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("i686-unknown-linux-gnu", false), ("x86_64-unknown-linux-gnu", true), ("x86_64-apple-darwin", true), - ("x86_64-pc-windows-gnu", true), + ("x86_64-pc-windows-gnu", false), ("x86_64-pc-windows-msvc", true), // tier 2 with host tools ("aarch64-unknown-linux-musl", false), @@ -227,7 +227,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), ("s390x-unknown-linux-gnu", false), - ("x86_64-pc-windows-gnullvm", true), + ("x86_64-pc-windows-gnullvm", false), ("x86_64-unknown-freebsd", false), ("x86_64-unknown-illumos", false), ("x86_64-unknown-linux-musl", false), @@ -284,8 +284,7 @@ impl Step for Llvm { LlvmBuildStatus::ShouldBuild(m) => m, }; - if builder.llvm_link_shared() && target.is_windows() && !target.ends_with("windows-gnullvm") - { + if builder.llvm_link_shared() && target.is_windows() && !target.is_windows_gnullvm() { panic!("shared linking to LLVM is not currently supported on {}", target.triple); } diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index ee10e36e1c37c..e69a658694753 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -612,16 +612,12 @@ auto: env: SCRIPT: make ci-mingw-x RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions - NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-bootstrap RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions - NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - name: dist-x86_64-msvc diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 17bedaa7b8266..da8e1d55f3ae3 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -47,12 +47,6 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac - # Stop /msys64/bin from being prepended to PATH by adding the bin directory manually. - # Note that this intentionally uses a Windows style path instead of the msys2 path to - # avoid being auto-translated into `/usr/bin`, which will not have the desired effect. - msys2Path="c:/msys64" - ciCommandAddPath "${msys2Path}/usr/bin" - case "${mingw_archive}" in *.7z) curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" @@ -73,12 +67,4 @@ if isWindows && isKnownToBeMingwBuild; then esac ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" - - # MSYS2 is not installed on AArch64 runners - if [[ "${CI_JOB_NAME}" != *aarch64-llvm* ]]; then - # Initialize mingw for the user. - # This should be done by github but isn't for some reason. - # (see https://github.com/actions/runner-images/issues/12600) - /c/msys64/usr/bin/bash -lc ' ' - fi fi diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 4cf95a04465a6..3da3571c27184 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -54,8 +54,8 @@ - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) + - [{arm,thumb}v4t-none-eabi](platform-support/armv4t-none-eabi.md) + - [{arm,thumb}v5te-none-eabi](platform-support/armv5te-none-eabi.md) - [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md) - [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md) - [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index c6d88762fb1b7..e5840be66230b 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -8,7 +8,8 @@ group, and all the information there applies. Both of these targets can be used on the Game Boy Advance (GBA), among other things. On the GBA, one should usually use the `thumb` target to get the best -overall performance. +overall performance. Note that this architecture only supports the old +Thumb-1 instruction set, not the later Thumb-2 instruction set. ## Target Maintainers diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md index e9f34d4ede8a1..10a69143bff62 100644 --- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -4,10 +4,12 @@ * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for any cpu in the Armv5TE architecture family, supporting -ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code -generation. +ARM/Thumb code interworking (aka `Arm`/`Thumb`), with `Arm` code as the +default code generation. -The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `T32`. +The `thumbv5te-none-eabi` target is the same as this one, but the instruction +set defaults to `Thumb`. Note that this architecture only supports the old +Thumb-1 instruction set, not the later Thumb-2 instruction set. See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all `arm-none-eabi` targets. diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 6597c3c70f691..c7c23d338e5b6 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -9,6 +9,9 @@ doctest = false [[bin]] name = "compiletest" path = "src/bin/main.rs" +# The compiletest binary crate is a tiny stub that shouldn't contain any unit +# tests of its own; all of the logic is in the library crate. +test = false [dependencies] # tidy-alphabetical-start diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 8e9c28e69ea7b..fed30415de569 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -34,12 +34,18 @@ mod needs; mod tests; pub struct DirectivesCache { + /// "Conditions" used by `ignore-*` and `only-*` directives, prepared in + /// advance so that they don't have to be evaluated repeatedly. + cfg_conditions: cfg::PreparedConditions, needs: CachedNeedsConditions, } impl DirectivesCache { pub fn load(config: &Config) -> Self { - Self { needs: CachedNeedsConditions::load(config) } + Self { + cfg_conditions: cfg::prepare_conditions(config), + needs: CachedNeedsConditions::load(config), + } } } @@ -1058,8 +1064,8 @@ pub(crate) fn make_test_description( }; } - decision!(cfg::handle_ignore(config, ln)); - decision!(cfg::handle_only(config, ln)); + decision!(cfg::handle_ignore(&cache.cfg_conditions, ln)); + decision!(cfg::handle_only(&cache.cfg_conditions, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); decision!(ignore_llvm(config, ln)); decision!(ignore_backends(config, ln)); diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 531763c1b3e25..62d10f14b98f2 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,12 +1,30 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; +use std::sync::{Arc, LazyLock}; use crate::common::{CompareMode, Config, Debugger}; use crate::directives::{DirectiveLine, IgnoreDecision}; const EXTRA_ARCHS: &[&str] = &["spirv"]; -pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "ignore-"); +const EXTERNAL_IGNORES_LIST: &[&str] = &[ + // tidy-alphabetical-start + "ignore-backends", + "ignore-gdb-version", + "ignore-llvm-version", + "ignore-pass", + // tidy-alphabetical-end +]; + +/// Directive names that begin with `ignore-`, but are disregarded by this +/// module because they are handled elsewhere. +pub(crate) static EXTERNAL_IGNORES_SET: LazyLock> = + LazyLock::new(|| EXTERNAL_IGNORES_LIST.iter().copied().collect()); + +pub(super) fn handle_ignore( + conditions: &PreparedConditions, + line: &DirectiveLine<'_>, +) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(conditions, line, "ignore-"); let line = line.display(); match parsed.outcome { @@ -18,13 +36,15 @@ pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> Ignore }, }, MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, - MatchOutcome::External => IgnoreDecision::Continue, - MatchOutcome::NotADirective => IgnoreDecision::Continue, + MatchOutcome::NotHandledHere => IgnoreDecision::Continue, } } -pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "only-"); +pub(super) fn handle_only( + conditions: &PreparedConditions, + line: &DirectiveLine<'_>, +) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(conditions, line, "only-"); let line = line.display(); match parsed.outcome { @@ -38,278 +58,208 @@ pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDe }, }, MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, - MatchOutcome::External => IgnoreDecision::Continue, - MatchOutcome::NotADirective => IgnoreDecision::Continue, + MatchOutcome::NotHandledHere => IgnoreDecision::Continue, } } /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `only-windows`. fn parse_cfg_name_directive<'a>( - config: &Config, + conditions: &PreparedConditions, line: &'a DirectiveLine<'a>, prefix: &str, ) -> ParsedNameDirective<'a> { let Some(name) = line.name.strip_prefix(prefix) else { - return ParsedNameDirective::not_a_directive(); + return ParsedNameDirective::not_handled_here(); }; + if prefix == "ignore-" && EXTERNAL_IGNORES_SET.contains(line.name) { + return ParsedNameDirective::not_handled_here(); + } + // FIXME(Zalathar): This currently allows either a space or a colon, and // treats any "value" after a colon as though it were a remark. // We should instead forbid the colon syntax for these directives. - let comment = line.remark_after_space().or_else(|| line.value_after_colon()); - - // Some of the matchers might be "" depending on what the target information is. To avoid - // problems we outright reject empty directives. - if name.is_empty() { - return ParsedNameDirective::not_a_directive(); + let comment = line + .remark_after_space() + .or_else(|| line.value_after_colon()) + .map(|c| c.trim().trim_start_matches('-').trim()); + + if let Some(cond) = conditions.conds.get(name) { + ParsedNameDirective { + pretty_reason: Some(Arc::clone(&cond.message_when_ignored)), + comment, + outcome: if cond.value { MatchOutcome::Match } else { MatchOutcome::NoMatch }, + } + } else { + ParsedNameDirective { pretty_reason: None, comment, outcome: MatchOutcome::Invalid } } +} - let mut outcome = MatchOutcome::Invalid; - let mut message = None; - - macro_rules! condition { - ( - name: $name:expr, - $(allowed_names: $allowed_names:expr,)? - $(condition: $condition:expr,)? - message: $($message:tt)* - ) => {{ - // This is not inlined to avoid problems with macro repetitions. - let format_message = || format!($($message)*); - - if outcome != MatchOutcome::Invalid { - // Ignore all other matches if we already found one - } else if $name.custom_matches(name) { - message = Some(format_message()); - if true $(&& $condition)? { - outcome = MatchOutcome::Match; - } else { - outcome = MatchOutcome::NoMatch; - } - } - $(else if $allowed_names.custom_contains(name) { - message = Some(format_message()); - outcome = MatchOutcome::NoMatch; - })? - }}; - } +/// Uses information about the current target (and all targets) to pre-compute +/// a value (true or false) for a number of "conditions". Those conditions can +/// then be used by `ignore-*` and `only-*` directives. +pub(crate) fn prepare_conditions(config: &Config) -> PreparedConditions { + let cfgs = config.target_cfgs(); + let current = &cfgs.current; - let target_cfgs = config.target_cfgs(); - let target_cfg = config.target_cfg(); + let mut builder = ConditionsBuilder::new(); - condition! { - name: "test", - message: "always" - } - condition! { - name: "auxiliary", - message: "used by another main test file" - } - condition! { - name: &config.target, - allowed_names: &target_cfgs.all_targets, - message: "when the target is {name}" + // Some condition names overlap (e.g. "macabi" is both an env and an ABI), + // so the order in which conditions are added is significant. + // Whichever condition registers that name _first_ will take precedence. + // (See `ConditionsBuilder::build`.) + + builder.cond("test", true, "always"); + builder.cond("auxiliary", true, "used by another main test file"); + + for target in &cfgs.all_targets { + builder.cond(target, *target == config.target, &format!("when the target is {target}")); } - condition! { - name: &target_cfg.os, - allowed_names: &target_cfgs.all_oses, - message: "when the operating system is {name}" + for os in &cfgs.all_oses { + builder.cond(os, *os == current.os, &format!("when the operating system is {os}")); } - condition! { - name: &target_cfg.env, - allowed_names: &target_cfgs.all_envs, - message: "when the target environment is {name}" + for env in &cfgs.all_envs { + builder.cond(env, *env == current.env, &format!("when the target environment is {env}")); } - condition! { - name: &target_cfg.os_and_env(), - allowed_names: &target_cfgs.all_oses_and_envs, - message: "when the operating system and target environment are {name}" + for os_and_env in &cfgs.all_oses_and_envs { + builder.cond( + os_and_env, + *os_and_env == current.os_and_env(), + &format!("when the operating system and target environment are {os_and_env}"), + ); } - condition! { - name: &target_cfg.abi, - allowed_names: &target_cfgs.all_abis, - message: "when the ABI is {name}" + for abi in &cfgs.all_abis { + builder.cond(abi, *abi == current.abi, &format!("when the ABI is {abi}")); } - condition! { - name: &target_cfg.arch, - allowed_names: ContainsEither { a: &target_cfgs.all_archs, b: &EXTRA_ARCHS }, - message: "when the architecture is {name}" + for arch in cfgs.all_archs.iter().map(String::as_str).chain(EXTRA_ARCHS.iter().copied()) { + builder.cond(arch, *arch == current.arch, &format!("when the architecture is {arch}")); } - condition! { - name: format!("{}bit", target_cfg.pointer_width), - allowed_names: &target_cfgs.all_pointer_widths, - message: "when the pointer width is {name}" + for n_bit in &cfgs.all_pointer_widths { + builder.cond( + n_bit, + *n_bit == format!("{}bit", current.pointer_width), + &format!("when the pointer width is {n_bit}"), + ); } - condition! { - name: &*target_cfg.families, - allowed_names: &target_cfgs.all_families, - message: "when the target family is {name}" + for family in &cfgs.all_families { + builder.cond( + family, + current.families.contains(family), + &format!("when the target family is {family}"), + ) } - condition! { - name: "thumb", - condition: config.target.starts_with("thumb"), - message: "when the architecture is part of the Thumb family" - } + builder.cond( + "thumb", + config.target.starts_with("thumb"), + "when the architecture is part of the Thumb family", + ); // The "arch" of `i586-` targets is "x86", so for more specific matching // we have to resort to a string-prefix check. - condition! { - name: "i586", - condition: config.matches_arch("i586"), - message: "when the subarchitecture is i586", - } - - condition! { - name: "apple", - condition: config.target.contains("apple"), - message: "when the target vendor is Apple" - } - - condition! { - name: "elf", - condition: target_cfg.binary_format == "elf", - message: "when the target binary format is ELF" - } - - condition! { - name: "enzyme", - condition: config.has_enzyme, - message: "when rustc is built with LLVM Enzyme" - } + builder.cond("i586", config.matches_arch("i586"), "when the subarchitecture is i586"); + // FIXME(Zalathar): Use proper target vendor information instead? + builder.cond("apple", config.target.contains("apple"), "when the target vendor is Apple"); + // FIXME(Zalathar): Support all known binary formats, not just ELF? + builder.cond("elf", current.binary_format == "elf", "when the target binary format is ELF"); + builder.cond("enzyme", config.has_enzyme, "when rustc is built with LLVM Enzyme"); // Technically the locally built compiler uses the "dev" channel rather than the "nightly" // channel, even though most people don't know or won't care about it. To avoid confusion, we // treat the "dev" channel as the "nightly" channel when processing the directive. - condition! { - name: if config.channel == "dev" { "nightly" } else { &config.channel }, - allowed_names: &["stable", "beta", "nightly"], - message: "when the release channel is {name}", + for channel in ["stable", "beta", "nightly"] { + let curr_channel = match config.channel.as_str() { + "dev" => "nightly", + ch => ch, + }; + builder.cond( + channel, + channel == curr_channel, + &format!("when the release channel is {channel}"), + ); + } + + builder.cond("cross-compile", config.target != config.host, "when cross-compiling"); + builder.cond("endian-big", config.is_big_endian(), "on big-endian targets"); + + for stage in ["stage0", "stage1", "stage2"] { + builder.cond( + stage, + stage == format!("stage{}", config.stage), + &format!("when the bootstrapping stage is {stage}"), + ); + } + + builder.cond("remote", config.remote_test_client.is_some(), "when running tests remotely"); + builder.cond( + "rustc-debug-assertions", + config.with_rustc_debug_assertions, + "when rustc is built with debug assertions", + ); + builder.cond( + "std-debug-assertions", + config.with_std_debug_assertions, + "when std is built with debug assertions", + ); + + for &debugger in Debugger::STR_VARIANTS { + builder.cond( + debugger, + Some(debugger) == config.debugger.as_ref().map(Debugger::to_str), + &format!("when the debugger is {debugger}"), + ); + } + + for &compare_mode in CompareMode::STR_VARIANTS { + builder.cond( + &format!("compare-mode-{compare_mode}"), + Some(compare_mode) == config.compare_mode.as_ref().map(CompareMode::to_str), + &format!("when comparing with compare-mode-{compare_mode}"), + ); } - condition! { - name: "cross-compile", - condition: config.target != config.host, - message: "when cross-compiling" - } - condition! { - name: "endian-big", - condition: config.is_big_endian(), - message: "on big-endian targets", - } - condition! { - name: format!("stage{}", config.stage).as_str(), - allowed_names: &["stage0", "stage1", "stage2"], - message: "when the bootstrapping stage is {name}", - } - condition! { - name: "remote", - condition: config.remote_test_client.is_some(), - message: "when running tests remotely", - } - condition! { - name: "rustc-debug-assertions", - condition: config.with_rustc_debug_assertions, - message: "when rustc is built with debug assertions", - } - condition! { - name: "std-debug-assertions", - condition: config.with_std_debug_assertions, - message: "when std is built with debug assertions", - } - condition! { - name: config.debugger.as_ref().map(|d| d.to_str()), - allowed_names: &Debugger::STR_VARIANTS, - message: "when the debugger is {name}", - } - condition! { - name: config.compare_mode - .as_ref() - .map(|d| format!("compare-mode-{}", d.to_str())), - allowed_names: ContainsPrefixed { - prefix: "compare-mode-", - inner: CompareMode::STR_VARIANTS, - }, - message: "when comparing with {name}", - } // Coverage tests run the same test file in multiple modes. // If a particular test should not be run in one of the modes, ignore it // with "ignore-coverage-map" or "ignore-coverage-run". - condition! { - name: config.mode.to_str(), - allowed_names: ["coverage-map", "coverage-run"], - message: "when the test mode is {name}", - } - condition! { - name: target_cfg.rustc_abi.as_ref().map(|abi| format!("rustc_abi-{abi}")).unwrap_or_default(), - allowed_names: ContainsPrefixed { - prefix: "rustc_abi-", - inner: target_cfgs.all_rustc_abis.clone(), - }, - message: "when the target `rustc_abi` is {name}", - } - - condition! { - name: "dist", - condition: std::env::var("COMPILETEST_ENABLE_DIST_TESTS") == Ok("1".to_string()), - message: "when performing tests on dist toolchain" - } - - if prefix == "ignore-" && outcome == MatchOutcome::Invalid { - // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest. - if name.starts_with("tidy-") { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-pass, as that is handled elsewhere. - if name == "pass" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-llvm-version, that has a custom syntax and is handled - // elsewhere. - if name == "llvm-version" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-llvm-version, that has a custom syntax and is handled - // elsewhere. - if name == "gdb-version" { - outcome = MatchOutcome::External; - } - - // Don't error out for ignore-backends,as it is handled elsewhere. - if name == "backends" { - outcome = MatchOutcome::External; - } - } - - ParsedNameDirective { - name: Some(name), - comment: comment.map(|c| c.trim().trim_start_matches('-').trim()), - outcome, - pretty_reason: message, - } + for test_mode in ["coverage-map", "coverage-run"] { + builder.cond( + test_mode, + test_mode == config.mode.to_str(), + &format!("when the test mode is {test_mode}"), + ); + } + + for rustc_abi in &cfgs.all_rustc_abis { + builder.cond( + &format!("rustc_abi-{rustc_abi}"), + Some(rustc_abi) == current.rustc_abi.as_ref(), + &format!("when the target `rustc_abi` is rustc_abi-{rustc_abi}"), + ); + } + + // FIXME(Zalathar): Ideally this should be configured by a command-line + // flag, not an environment variable. + builder.cond( + "dist", + std::env::var("COMPILETEST_ENABLE_DIST_TESTS").as_deref() == Ok("1"), + "when performing tests on dist toolchain", + ); + + builder.build() } /// The result of parse_cfg_name_directive. #[derive(Clone, PartialEq, Debug)] pub(super) struct ParsedNameDirective<'a> { - pub(super) name: Option<&'a str>, - pub(super) pretty_reason: Option, + pub(super) pretty_reason: Option>, pub(super) comment: Option<&'a str>, pub(super) outcome: MatchOutcome, } impl ParsedNameDirective<'_> { - fn not_a_directive() -> Self { - Self { - name: None, - pretty_reason: None, - comment: None, - outcome: MatchOutcome::NotADirective, - } + fn not_handled_here() -> Self { + Self { pretty_reason: None, comment: None, outcome: MatchOutcome::NotHandledHere } } } @@ -321,92 +271,59 @@ pub(super) enum MatchOutcome { Match, /// The directive was invalid. Invalid, - /// The directive is handled by other parts of our tooling. - External, - /// The line is not actually a directive. - NotADirective, -} - -trait CustomContains { - fn custom_contains(&self, item: &str) -> bool; -} - -impl CustomContains for HashSet { - fn custom_contains(&self, item: &str) -> bool { - self.contains(item) - } -} - -impl CustomContains for &[&str] { - fn custom_contains(&self, item: &str) -> bool { - self.contains(&item) - } -} - -impl CustomContains for [&str; N] { - fn custom_contains(&self, item: &str) -> bool { - self.contains(&item) - } -} - -struct ContainsPrefixed { - prefix: &'static str, - inner: T, + /// The directive should be ignored by this module, because it is handled elsewhere. + NotHandledHere, } -impl CustomContains for ContainsPrefixed { - fn custom_contains(&self, item: &str) -> bool { - match item.strip_prefix(self.prefix) { - Some(stripped) => self.inner.custom_contains(stripped), - None => false, - } - } +#[derive(Debug)] +pub(crate) struct PreparedConditions { + /// Maps the "bare" name of each condition to a structure indicating + /// whether the condition is true or false for the target being tested. + conds: HashMap, Cond>, } -struct ContainsEither<'a, A: CustomContains, B: CustomContains> { - a: &'a A, - b: &'a B, -} +#[derive(Debug)] +struct Cond { + /// Bare condition name without an ignore/only prefix, e.g. `aarch64` or `windows`. + bare_name: Arc, -impl CustomContains for ContainsEither<'_, A, B> { - fn custom_contains(&self, item: &str) -> bool { - self.a.custom_contains(item) || self.b.custom_contains(item) - } -} + /// Is this condition true or false for the target being tested, based on + /// the config that was used to prepare these conditions? + /// + /// For example, the condition `windows` is true on Windows targets. + value: bool, -trait CustomMatches { - fn custom_matches(&self, name: &str) -> bool; + /// Message fragment to show when a test is ignored based on this condition + /// being true or false, e.g. "when the architecture is aarch64". + message_when_ignored: Arc, } -impl CustomMatches for &str { - fn custom_matches(&self, name: &str) -> bool { - name == *self - } +struct ConditionsBuilder { + conds: Vec, } -impl CustomMatches for String { - fn custom_matches(&self, name: &str) -> bool { - name == self - } -} - -impl CustomMatches for &[T] { - fn custom_matches(&self, name: &str) -> bool { - self.iter().any(|m| m.custom_matches(name)) - } -} - -impl CustomMatches for [T; N] { - fn custom_matches(&self, name: &str) -> bool { - self.iter().any(|m| m.custom_matches(name)) - } -} - -impl CustomMatches for Option { - fn custom_matches(&self, name: &str) -> bool { - match self { - Some(inner) => inner.custom_matches(name), - None => false, - } +impl ConditionsBuilder { + fn new() -> Self { + Self { conds: vec![] } + } + + fn cond(&mut self, bare_name: &str, value: bool, message_when_ignored: &str) { + self.conds.push(Cond { + bare_name: Arc::::from(bare_name), + value, + message_when_ignored: Arc::::from(message_when_ignored), + }); + } + + fn build(self) -> PreparedConditions { + let conds = self + .conds + .into_iter() + // Build the map in reverse order, so that conditions declared + // earlier have priority over ones declared later. + .rev() + .map(|cond| (Arc::clone(&cond.bare_name), cond)) + .collect::>(); + PreparedConditions { conds } } } diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index bb8002de391e1..90e2cb77e304c 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -26,6 +26,19 @@ fn handler_names() { ); } +#[test] +fn external_ignores() { + let unknown_names = directives::cfg::EXTERNAL_IGNORES_SET + .difference(&KNOWN_DIRECTIVE_NAMES_SET) + .into_iter() + .collect::>(); + + assert!( + unknown_names.is_empty(), + "Directive names not in `directive_names.rs`: {unknown_names:#?}" + ); +} + fn make_test_description( config: &Config, name: String, diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index bdeadf8a5c05e..0dff383be8255 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -1,3 +1,8 @@ +//! This tests that `next` skips over macro invocations correctly. +//! The `#locN` markers have no meaning for compiletest, we include them just +//! so that the debugger prints them when printing the current source location, +//! and we can match on them for testing purposes. + //@ ignore-android //@ min-lldb-version: 1800 //@ min-gdb-version: 13.0 @@ -68,6 +73,7 @@ extern crate macro_stepping; // exports new_scope!() //@ lldb-command:next //@ lldb-command:frame select //@ lldb-check:[...] #loc5 [...] +// FIXME: what about loc6? //@ lldb-command:continue //@ lldb-command:step diff --git a/triagebot.toml b/triagebot.toml index f901dc7efc1e6..6ad8dd6b4c886 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1427,6 +1427,7 @@ compiler = [ "@JonathanBrouwer", "@lcnr", "@madsmtm", + "@mati865", "@Nadrieril", "@nnethercote", "@oli-obk",