Auto merge of #149531 - Zalathar:rollup-15y580s, r=Zalathar
Rollup of 8 pull requests Successful merges: - rust-lang/rust#145628 ([std][BTree] Fix behavior of `::append` to match documentation, `::insert`, and `::extend`) - rust-lang/rust#149241 (Fix armv4t- and armv5te- bare metal targets) - rust-lang/rust#149470 (compiletest: Prepare ignore/only conditions once in advance, without a macro) - rust-lang/rust#149507 (Mark windows-gnu* as lacking build with assertions) - rust-lang/rust#149508 (Prefer helper functions to identify MinGW targets) - rust-lang/rust#149516 (Stop adding MSYS2 to PATH) - rust-lang/rust#149525 (debuginfo/macro-stepping test: extend comments) - rust-lang/rust#149526 (Add myself (mati865) to the review rotation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
63b1db0580
40 changed files with 394 additions and 519 deletions
|
|
@ -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};
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1181,6 +1181,10 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
///
|
||||
/// 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
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<T: PartialEq> PartialEq for Governed<'_, T> {
|
|||
}
|
||||
|
||||
impl<T: Eq> 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<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for IdBased {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.id.cmp(&other.id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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<HashSet<&str>> =
|
||||
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());
|
||||
let comment = line
|
||||
.remark_after_space()
|
||||
.or_else(|| line.value_after_colon())
|
||||
.map(|c| c.trim().trim_start_matches('-').trim());
|
||||
|
||||
// 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();
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 mut builder = ConditionsBuilder::new();
|
||||
|
||||
// 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}"));
|
||||
}
|
||||
for os in &cfgs.all_oses {
|
||||
builder.cond(os, *os == current.os, &format!("when the operating system is {os}"));
|
||||
}
|
||||
for env in &cfgs.all_envs {
|
||||
builder.cond(env, *env == current.env, &format!("when the target environment is {env}"));
|
||||
}
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
for abi in &cfgs.all_abis {
|
||||
builder.cond(abi, *abi == current.abi, &format!("when the ABI is {abi}"));
|
||||
}
|
||||
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}"));
|
||||
}
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
for family in &cfgs.all_families {
|
||||
builder.cond(
|
||||
family,
|
||||
current.families.contains(family),
|
||||
&format!("when the target family is {family}"),
|
||||
)
|
||||
}
|
||||
|
||||
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;
|
||||
})?
|
||||
}};
|
||||
}
|
||||
|
||||
let target_cfgs = config.target_cfgs();
|
||||
let target_cfg = config.target_cfg();
|
||||
|
||||
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}"
|
||||
}
|
||||
condition! {
|
||||
name: &target_cfg.os,
|
||||
allowed_names: &target_cfgs.all_oses,
|
||||
message: "when the operating system is {name}"
|
||||
}
|
||||
condition! {
|
||||
name: &target_cfg.env,
|
||||
allowed_names: &target_cfgs.all_envs,
|
||||
message: "when the target environment is {name}"
|
||||
}
|
||||
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}"
|
||||
}
|
||||
condition! {
|
||||
name: &target_cfg.abi,
|
||||
allowed_names: &target_cfgs.all_abis,
|
||||
message: "when the ABI is {name}"
|
||||
}
|
||||
condition! {
|
||||
name: &target_cfg.arch,
|
||||
allowed_names: ContainsEither { a: &target_cfgs.all_archs, b: &EXTRA_ARCHS },
|
||||
message: "when the architecture is {name}"
|
||||
}
|
||||
condition! {
|
||||
name: format!("{}bit", target_cfg.pointer_width),
|
||||
allowed_names: &target_cfgs.all_pointer_widths,
|
||||
message: "when the pointer width is {name}"
|
||||
}
|
||||
condition! {
|
||||
name: &*target_cfg.families,
|
||||
allowed_names: &target_cfgs.all_families,
|
||||
message: "when the target family is {name}"
|
||||
}
|
||||
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
|
||||
condition! {
|
||||
name: "cross-compile",
|
||||
condition: config.target != config.host,
|
||||
message: "when cross-compiling"
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
condition! {
|
||||
name: "endian-big",
|
||||
condition: config.is_big_endian(),
|
||||
message: "on big-endian targets",
|
||||
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
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}",
|
||||
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
|
||||
// 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}",
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
|
||||
condition! {
|
||||
name: "dist",
|
||||
condition: std::env::var("COMPILETEST_ENABLE_DIST_TESTS") == Ok("1".to_string()),
|
||||
message: "when performing tests on dist toolchain"
|
||||
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}"),
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// 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",
|
||||
);
|
||||
|
||||
// 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,
|
||||
}
|
||||
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<String>,
|
||||
pub(super) pretty_reason: Option<Arc<str>>,
|
||||
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,
|
||||
/// The directive should be ignored by this module, because it is handled elsewhere.
|
||||
NotHandledHere,
|
||||
}
|
||||
|
||||
trait CustomContains {
|
||||
fn custom_contains(&self, item: &str) -> bool;
|
||||
#[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<Arc<str>, Cond>,
|
||||
}
|
||||
|
||||
impl CustomContains for HashSet<String> {
|
||||
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<const N: usize> CustomContains for [&str; N] {
|
||||
fn custom_contains(&self, item: &str) -> bool {
|
||||
self.contains(&item)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContainsPrefixed<T: CustomContains> {
|
||||
prefix: &'static str,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T: CustomContains> CustomContains for ContainsPrefixed<T> {
|
||||
fn custom_contains(&self, item: &str) -> bool {
|
||||
match item.strip_prefix(self.prefix) {
|
||||
Some(stripped) => self.inner.custom_contains(stripped),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContainsEither<'a, A: CustomContains, B: CustomContains> {
|
||||
a: &'a A,
|
||||
b: &'a B,
|
||||
}
|
||||
|
||||
impl<A: CustomContains, B: CustomContains> CustomContains for ContainsEither<'_, A, B> {
|
||||
fn custom_contains(&self, item: &str) -> bool {
|
||||
self.a.custom_contains(item) || self.b.custom_contains(item)
|
||||
}
|
||||
}
|
||||
|
||||
trait CustomMatches {
|
||||
fn custom_matches(&self, name: &str) -> bool;
|
||||
}
|
||||
|
||||
impl CustomMatches for &str {
|
||||
fn custom_matches(&self, name: &str) -> bool {
|
||||
name == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomMatches for String {
|
||||
fn custom_matches(&self, name: &str) -> bool {
|
||||
name == self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CustomMatches> CustomMatches for &[T] {
|
||||
fn custom_matches(&self, name: &str) -> bool {
|
||||
self.iter().any(|m| m.custom_matches(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: CustomMatches> CustomMatches for [T; N] {
|
||||
fn custom_matches(&self, name: &str) -> bool {
|
||||
self.iter().any(|m| m.custom_matches(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CustomMatches> CustomMatches for Option<T> {
|
||||
fn custom_matches(&self, name: &str) -> bool {
|
||||
match self {
|
||||
Some(inner) => inner.custom_matches(name),
|
||||
None => false,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct Cond {
|
||||
/// Bare condition name without an ignore/only prefix, e.g. `aarch64` or `windows`.
|
||||
bare_name: Arc<str>,
|
||||
|
||||
/// 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,
|
||||
|
||||
/// 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<str>,
|
||||
}
|
||||
|
||||
struct ConditionsBuilder {
|
||||
conds: Vec<Cond>,
|
||||
}
|
||||
|
||||
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::<str>::from(bare_name),
|
||||
value,
|
||||
message_when_ignored: Arc::<str>::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::<HashMap<_, _>>();
|
||||
PreparedConditions { conds }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::<BTreeSet<_>>();
|
||||
|
||||
assert!(
|
||||
unknown_names.is_empty(),
|
||||
"Directive names not in `directive_names.rs`: {unknown_names:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
fn make_test_description(
|
||||
config: &Config,
|
||||
name: String,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1427,6 +1427,7 @@ compiler = [
|
|||
"@JonathanBrouwer",
|
||||
"@lcnr",
|
||||
"@madsmtm",
|
||||
"@mati865",
|
||||
"@Nadrieril",
|
||||
"@nnethercote",
|
||||
"@oli-obk",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue