Auto merge of #153865 - Zalathar:rollup-tKflfa5, r=Zalathar

Rollup of 5 pull requests

Successful merges:

 - rust-lang/rust#153769 (target specs: stricter checks for LLVM ABI values, and correlate that with cfg(target_abi))
 - rust-lang/rust#153811 (Don't pass a separate `DepKind` to `query_feed`)
 - rust-lang/rust#153817 (relocate several ui tests)
 - rust-lang/rust#153840 (tests/debuginfo/basic-stepping.rs: Add cdb test)
 - rust-lang/rust#153858 (Use named fields in ChunkedBitSet's `Chunk::Mixed`)
This commit is contained in:
bors
2026-03-14 13:39:01 +00:00
31 changed files with 387 additions and 127 deletions
@@ -294,18 +294,13 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
_ => elf::EF_MIPS_ARCH_64R2,
};
// If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS,
// which is the only "true" 32-bit option that LLVM supports.
// Use the explicitly given ABI.
match sess.target.options.llvm_abiname.as_ref() {
"o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2,
"n64" if !is_32bit => {}
"" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"),
s if is_32bit => {
sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s))
}
s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)),
// The rest is invalid (which is already ensured by the target spec check).
s => bug!("invalid LLVM ABI `{}` for MIPS target", s),
};
if sess.target.options.relocation_model != RelocModel::Static {
+44 -37
View File
@@ -509,14 +509,20 @@ enum Chunk {
/// to store the length, which would make this type larger. These excess
/// words are always zero, as are any excess bits in the final in-use word.
///
/// The `ChunkSize` field is the count of 1s set in the chunk, and
/// must satisfy `0 < count < chunk_domain_size`.
///
/// The words are within an `Rc` because it's surprisingly common to
/// duplicate an entire chunk, e.g. in `ChunkedBitSet::clone_from()`, or
/// when a `Mixed` chunk is union'd into a `Zeros` chunk. When we do need
/// to modify a chunk we use `Rc::make_mut`.
Mixed(ChunkSize, Rc<[Word; CHUNK_WORDS]>),
Mixed {
/// Count of set bits (1s) in this chunk's words.
///
/// Invariant: `0 < ones_count < chunk_domain_size`.
///
/// Tracking this separately allows individual insert/remove calls to
/// know that the chunk has become all-zeroes or all-ones, in O(1) time.
ones_count: ChunkSize,
words: Rc<[Word; CHUNK_WORDS]>,
},
}
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -613,7 +619,7 @@ pub fn contains(&self, elem: T) -> bool {
match &chunk {
Zeros => false,
Ones => true,
Mixed(_, words) => {
Mixed { ones_count: _, words } => {
let (word_index, mask) = chunk_word_index_and_mask(elem);
(words[word_index] & mask) != 0
}
@@ -644,19 +650,19 @@ pub fn insert(&mut self, elem: T) -> bool {
let (word_index, mask) = chunk_word_index_and_mask(elem);
words_ref[word_index] |= mask;
*chunk = Mixed(1, words);
*chunk = Mixed { ones_count: 1, words };
} else {
*chunk = Ones;
}
true
}
Ones => false,
Mixed(ref mut count, ref mut words) => {
Mixed { ref mut ones_count, ref mut words } => {
// We skip all the work if the bit is already set.
let (word_index, mask) = chunk_word_index_and_mask(elem);
if (words[word_index] & mask) == 0 {
*count += 1;
if *count < chunk_domain_size {
*ones_count += 1;
if *ones_count < chunk_domain_size {
let words = Rc::make_mut(words);
words[word_index] |= mask;
} else {
@@ -702,18 +708,18 @@ pub fn remove(&mut self, elem: T) -> bool {
);
let (word_index, mask) = chunk_word_index_and_mask(elem);
words_ref[word_index] &= !mask;
*chunk = Mixed(chunk_domain_size - 1, words);
*chunk = Mixed { ones_count: chunk_domain_size - 1, words };
} else {
*chunk = Zeros;
}
true
}
Mixed(ref mut count, ref mut words) => {
Mixed { ref mut ones_count, ref mut words } => {
// We skip all the work if the bit is already clear.
let (word_index, mask) = chunk_word_index_and_mask(elem);
if (words[word_index] & mask) != 0 {
*count -= 1;
if *count > 0 {
*ones_count -= 1;
if *ones_count > 0 {
let words = Rc::make_mut(words);
words[word_index] &= !mask;
} else {
@@ -732,7 +738,7 @@ fn chunk_iter(&self, chunk_index: usize) -> ChunkIter<'_> {
match self.chunks.get(chunk_index) {
Some(Zeros) => ChunkIter::Zeros,
Some(Ones) => ChunkIter::Ones(0..chunk_domain_size as usize),
Some(Mixed(_, words)) => {
Some(Mixed { ones_count: _, words }) => {
let num_words = num_words(chunk_domain_size as usize);
ChunkIter::Mixed(BitIter::new(&words[0..num_words]))
}
@@ -765,14 +771,14 @@ fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
match (&mut self_chunk, &other_chunk) {
(_, Zeros) | (Ones, _) => {}
(Zeros, _) | (Mixed(..), Ones) => {
(Zeros, _) | (Mixed { .. }, Ones) => {
// `other_chunk` fully overwrites `self_chunk`
*self_chunk = other_chunk.clone();
changed = true;
}
(
Mixed(self_chunk_count, self_chunk_words),
Mixed(_other_chunk_count, other_chunk_words),
Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
Mixed { ones_count: _, words: other_chunk_words },
) => {
// First check if the operation would change
// `self_chunk.words`. If not, we can avoid allocating some
@@ -807,8 +813,8 @@ fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
op,
);
debug_assert!(has_changed);
*self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == chunk_domain_size {
*self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_ones == chunk_domain_size {
*self_chunk = Ones;
}
changed = true;
@@ -839,11 +845,11 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
match (&mut self_chunk, &other_chunk) {
(Zeros, _) | (_, Zeros) => {}
(Ones | Mixed(..), Ones) => {
(Ones | Mixed { .. }, Ones) => {
changed = true;
*self_chunk = Zeros;
}
(Ones, Mixed(other_chunk_count, other_chunk_words)) => {
(Ones, Mixed { ones_count: other_chunk_ones, words: other_chunk_words }) => {
changed = true;
let num_words = num_words(chunk_domain_size as usize);
debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS);
@@ -854,16 +860,17 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
*word = !*word & tail_mask;
tail_mask = Word::MAX;
}
let self_chunk_count = chunk_domain_size - *other_chunk_count;
let self_chunk_ones = chunk_domain_size - *other_chunk_ones;
debug_assert_eq!(
self_chunk_count,
self_chunk_ones,
count_ones(&self_chunk_words[0..num_words]) as ChunkSize
);
*self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words));
*self_chunk =
Mixed { ones_count: self_chunk_ones, words: Rc::new(self_chunk_words) };
}
(
Mixed(self_chunk_count, self_chunk_words),
Mixed(_other_chunk_count, other_chunk_words),
Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
Mixed { ones_count: _, words: other_chunk_words },
) => {
// See `ChunkedBitSet::union` for details on what is happening here.
let num_words = num_words(chunk_domain_size as usize);
@@ -883,8 +890,8 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
op,
);
debug_assert!(has_changed);
*self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_ones == 0 {
*self_chunk = Zeros;
}
changed = true;
@@ -915,13 +922,13 @@ fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
match (&mut self_chunk, &other_chunk) {
(Zeros, _) | (_, Ones) => {}
(Ones, Zeros | Mixed(..)) | (Mixed(..), Zeros) => {
(Ones, Zeros | Mixed { .. }) | (Mixed { .. }, Zeros) => {
changed = true;
*self_chunk = other_chunk.clone();
}
(
Mixed(self_chunk_count, self_chunk_words),
Mixed(_other_chunk_count, other_chunk_words),
Mixed { ones_count: self_chunk_ones, words: self_chunk_words },
Mixed { ones_count: _, words: other_chunk_words },
) => {
// See `ChunkedBitSet::union` for details on what is happening here.
let num_words = num_words(chunk_domain_size as usize);
@@ -941,8 +948,8 @@ fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
op,
);
debug_assert!(has_changed);
*self_chunk_count = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk_ones = count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_ones == 0 {
*self_chunk = Zeros;
}
changed = true;
@@ -1023,11 +1030,11 @@ fn assert_valid(&self, chunk_domain_size: ChunkSize) {
assert!(chunk_domain_size as usize <= CHUNK_BITS);
match *self {
Zeros | Ones => {}
Mixed(count, ref words) => {
assert!(0 < count && count < chunk_domain_size);
Mixed { ones_count, ref words } => {
assert!(0 < ones_count && ones_count < chunk_domain_size);
// Check the number of set bits matches `count`.
assert_eq!(count_ones(words.as_slice()) as ChunkSize, count);
assert_eq!(count_ones(words.as_slice()) as ChunkSize, ones_count);
// Check the not-in-use words are all zeroed.
let num_words = num_words(chunk_domain_size as usize);
@@ -1043,7 +1050,7 @@ fn count(&self, chunk_domain_size: ChunkSize) -> usize {
match *self {
Zeros => 0,
Ones => chunk_domain_size as usize,
Mixed(count, _) => count as usize,
Mixed { ones_count, words: _ } => usize::from(ones_count),
}
}
}
+12 -12
View File
@@ -162,16 +162,16 @@ fn chunked_bitset() {
assert!(!b100.contains(20) && b100.contains(30) && !b100.contains(99) && b100.contains(50));
assert_eq!(
b100.chunks(),
vec![Mixed(
97,
vec![Mixed {
ones_count: 97,
#[rustfmt::skip]
Rc::new([
words: Rc::new([
0b11111111_11111111_11111110_11111111_11111111_11101111_11111111_11111111,
0b00000000_00000000_00000000_00000111_11111111_11111111_11111111_11111111,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
])
)],
}],
);
b100.assert_valid();
let mut num_removed = 0;
@@ -228,14 +228,14 @@ fn chunked_bitset() {
b4096.chunks(),
#[rustfmt::skip]
vec![
Mixed(1, Rc::new([
Mixed { ones_count: 1, words:Rc::new([
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])),
Mixed(1, Rc::new([
])},
Mixed { ones_count: 1, words: Rc::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000
])),
])},
],
);
assert_eq!(b4096.count(), 2);
@@ -265,14 +265,14 @@ fn chunked_bitset() {
#[rustfmt::skip]
vec![
Zeros,
Mixed(1, Rc::new([
Mixed { ones_count: 1, words: Rc::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100_0000_0000_0000, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
])),
Mixed(1, Rc::new([
])},
Mixed { ones_count: 1, words: Rc::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0100, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
])),
])},
Zeros,
Zeros,
],
+1 -1
View File
@@ -120,7 +120,7 @@
self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput,
SizedTraitKind, Ty, TyCtxt, TyCtxtFeed,
};
use crate::{dep_graph, mir, thir};
use crate::{mir, thir};
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
+13 -13
View File
@@ -4,7 +4,7 @@
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use crate::dep_graph;
use crate::dep_graph::{DepKind, DepNodeKey};
use crate::dep_graph::DepNodeKey;
use crate::query::erase::{self, Erasable, Erased};
use crate::query::plumbing::QueryVTable;
use crate::query::{EnsureMode, QueryCache, QueryMode};
@@ -98,26 +98,26 @@ pub(crate) fn query_ensure_result<'tcx, C, T>(
}
}
/// Common implementation of query feeding, used by `define_feedable!`.
/// "Feeds" a feedable query by adding a given key/value pair to its in-memory cache.
/// Called by macro-generated methods of [`rustc_middle::ty::TyCtxtFeed`].
pub(crate) fn query_feed<'tcx, C>(
tcx: TyCtxt<'tcx>,
dep_kind: DepKind,
query_vtable: &QueryVTable<'tcx, C>,
query: &'tcx QueryVTable<'tcx, C>,
key: C::Key,
value: C::Value,
) where
C: QueryCache,
C::Key: DepNodeKey<'tcx>,
{
let format_value = query_vtable.format_value;
let format_value = query.format_value;
// Check whether the in-memory cache already has a value for this key.
match try_get_cached(tcx, &query_vtable.cache, key) {
match try_get_cached(tcx, &query.cache, key) {
Some(old) => {
// The query already has a cached value for this key.
// That's OK if both values are the same, i.e. they have the same hash,
// so now we check their hashes.
if let Some(hash_value_fn) = query_vtable.hash_value_fn {
if let Some(hash_value_fn) = query.hash_value_fn {
let (old_hash, value_hash) = tcx.with_stable_hashing_context(|ref mut hcx| {
(hash_value_fn(hcx, &old), hash_value_fn(hcx, &value))
});
@@ -126,7 +126,7 @@ pub(crate) fn query_feed<'tcx, C>(
// results is tainted by errors. In this case, delay a bug to
// ensure compilation is doomed, and keep the `old` value.
tcx.dcx().delayed_bug(format!(
"Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
"Trying to feed an already recorded value for query {query:?} key={key:?}:\n\
old value: {old}\nnew value: {value}",
old = format_value(&old),
value = format_value(&value),
@@ -137,7 +137,7 @@ pub(crate) fn query_feed<'tcx, C>(
// If feeding the same value multiple times needs to be supported,
// the query should not be marked `no_hash`.
bug!(
"Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
"Trying to feed an already recorded value for query {query:?} key={key:?}:\n\
old value: {old}\nnew value: {value}",
old = format_value(&old),
value = format_value(&value),
@@ -147,15 +147,15 @@ pub(crate) fn query_feed<'tcx, C>(
None => {
// There is no cached value for this key, so feed the query by
// adding the provided value to the cache.
let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key);
let dep_node = dep_graph::DepNode::construct(tcx, query.dep_kind, &key);
let dep_node_index = tcx.dep_graph.with_feed_task(
dep_node,
tcx,
&value,
query_vtable.hash_value_fn,
query_vtable.format_value,
query.hash_value_fn,
query.format_value,
);
query_vtable.cache.complete(key, value, dep_node_index);
query.cache.complete(key, value, dep_node_index);
}
}
}
@@ -493,7 +493,6 @@ pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
let erased_value = $name::provided_to_erased(self.tcx, value);
$crate::query::inner::query_feed(
self.tcx,
dep_graph::DepKind::$name,
&self.tcx.query_system.query_vtables.$name,
key,
erased_value,
@@ -127,7 +127,12 @@ pub(crate) fn base(
let link_env_remove = link_env_remove(&os);
let unversioned_llvm_target = unversioned_llvm_target(&os, arch, env);
let mut opts = TargetOptions {
llvm_floatabi: Some(FloatAbi::Hard),
llvm_floatabi: if arch.target_arch() == crate::spec::Arch::Arm {
Some(FloatAbi::Hard)
} else {
// `llvm_floatabi` makes no sense on x86 and aarch64.
None
},
os,
env: env.target_env(),
abi: env.target_abi(),
+249 -40
View File
@@ -1005,7 +1005,7 @@ pub enum FloatAbi {
pub enum RustcAbi {
/// On x86-32 only: make use of SSE and SSE2 for ABI purposes.
X86Sse2 = "x86-sse2",
/// On x86-32/64 and S390x: do not use any FPU or SIMD registers for the ABI.
/// On x86-32/64, aarch64, and S390x: do not use any FPU or SIMD registers for the ABI.
Softfloat = "softfloat", "x86-softfloat",
}
@@ -3183,69 +3183,277 @@ macro_rules! check_matches {
);
}
// Check that RISC-V targets always specify which ABI they use,
// and that ARM targets specify their float ABI.
// Check ABI flag consistency, for the architectures where we have proper ABI treatment.
// To ensure targets are trated consistently, please consult with the team before allowing
// new cases.
match self.arch {
Arch::RiscV32 => {
Arch::X86 => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on x86-32");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-32");
check_matches!(
&*self.llvm_abiname,
"ilp32" | "ilp32f" | "ilp32d" | "ilp32e",
"invalid RISC-V ABI name: {}",
(&self.rustc_abi, &self.abi),
// FIXME: we do not currently set a target_abi for softfloat targets here,
// but we probably should, so we already allow it.
(Some(RustcAbi::Softfloat), Abi::SoftFloat | Abi::Unspecified | Abi::Other(_))
| (
Some(RustcAbi::X86Sse2) | None,
Abi::Uwp | Abi::Llvm | Abi::Sim | Abi::Unspecified | Abi::Other(_)
),
"invalid x86-32 Rust-specific ABI and `cfg(target_abi)` combination:\n\
Rust-specific ABI: {:?}\n\
cfg(target_abi): {}",
self.rustc_abi,
self.abi,
);
}
Arch::X86_64 => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on x86-64");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-64");
// FIXME: we do not currently set a target_abi for softfloat targets here, but we
// probably should, so we already allow it.
// FIXME: Ensure that target_abi = "x32" correlates with actually using that ABI.
// Do any of the others need a similar check?
check_matches!(
(&self.rustc_abi, &self.abi),
(Some(RustcAbi::Softfloat), Abi::SoftFloat | Abi::Unspecified | Abi::Other(_))
| (
None,
Abi::X32
| Abi::Llvm
| Abi::Fortanix
| Abi::Uwp
| Abi::MacAbi
| Abi::Sim
| Abi::Unspecified
| Abi::Other(_)
),
"invalid x86-64 Rust-specific ABI and `cfg(target_abi)` combination:\n\
Rust-specific ABI: {:?}\n\
cfg(target_abi): {}",
self.rustc_abi,
self.abi,
);
}
Arch::RiscV32 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
check_matches!(
(&*self.llvm_abiname, &self.abi),
("ilp32", Abi::Unspecified | Abi::Other(_))
| ("ilp32f", Abi::Unspecified | Abi::Other(_))
| ("ilp32d", Abi::Unspecified | Abi::Other(_))
| ("ilp32e", Abi::Ilp32e),
"invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::RiscV64 => {
// Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI.
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
check_matches!(
&*self.llvm_abiname,
"lp64" | "lp64f" | "lp64d" | "lp64e",
"invalid RISC-V ABI name: {}",
(&*self.llvm_abiname, &self.abi),
("lp64", Abi::Unspecified | Abi::Other(_))
| ("lp64f", Abi::Unspecified | Abi::Other(_))
| ("lp64d", Abi::Unspecified | Abi::Other(_))
| ("lp64e", Abi::Unspecified | Abi::Other(_)),
"invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::Arm => {
check!(
self.llvm_floatabi.is_some(),
"ARM targets must set `llvm-floatabi` to `hard` or `soft`",
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on ARM");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on ARM");
check_matches!(
(&self.llvm_floatabi, &self.abi),
(
Some(FloatAbi::Hard),
Abi::EabiHf | Abi::Uwp | Abi::Unspecified | Abi::Other(_)
) | (Some(FloatAbi::Soft), Abi::Eabi),
"Invalid combination of float ABI and `cfg(target_abi)` for ARM target\n\
float ABI: {:?}\n\
cfg(target_abi): {}",
self.llvm_floatabi,
self.abi,
)
}
// PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2
Arch::AArch64 => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on aarch64");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64");
// FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI.
// Do any of the others need a similar check?
check_matches!(
(&self.rustc_abi, &self.abi),
(Some(RustcAbi::Softfloat), Abi::SoftFloat)
| (
None,
Abi::Ilp32
| Abi::Llvm
| Abi::MacAbi
| Abi::Sim
| Abi::Uwp
| Abi::Unspecified
| Abi::Other(_)
),
"invalid aarch64 Rust-specific ABI and `cfg(target_abi)` combination:\n\
Rust-specific ABI: {:?}\n\
cfg(target_abi): {}",
self.rustc_abi,
self.abi,
);
}
Arch::PowerPC => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on PowerPC");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC");
// FIXME: Check that `target_abi` matches the actually configured ABI (with or
// without SPE).
check_matches!(
self.abi,
Abi::Spe | Abi::Unspecified | Abi::Other(_),
"invalid `target_abi` for PowerPC"
);
}
Arch::PowerPC64 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC64");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC64");
// PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2
if self.os == Os::Aix {
check!(
self.llvm_abiname.is_empty(),
"AIX targets always use the AIX ABI and `llvm_abiname` should be left empty",
// FIXME: Check that `target_abi` matches the actually configured ABI
// (vec-default vs vec-ext).
check_matches!(
(&*self.llvm_abiname, &self.abi),
("", Abi::VecDefault | Abi::VecExtAbi),
"invalid PowerPC64 AIX ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
} else if self.endian == Endian::Big {
check_matches!(
&*self.llvm_abiname,
"elfv1" | "elfv2",
"invalid PowerPC64 ABI name: {}",
(&*self.llvm_abiname, &self.abi),
("elfv1", Abi::ElfV1) | ("elfv2", Abi::ElfV2),
"invalid PowerPC64 big-endian ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
} else {
check!(
self.llvm_abiname == "elfv2",
"little-endian PowerPC64 targets only support the `elfv2` ABI",
check_matches!(
(&*self.llvm_abiname, &self.abi),
("elfv2", Abi::ElfV2),
"invalid PowerPC64 little-endian ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
}
_ => {}
}
// Check consistency of Rust ABI declaration.
if let Some(rust_abi) = self.rustc_abi {
match rust_abi {
RustcAbi::X86Sse2 => check_matches!(
self.arch,
Arch::X86,
"`x86-sse2` ABI is only valid for x86-32 targets"
),
RustcAbi::Softfloat => check_matches!(
self.arch,
Arch::X86 | Arch::X86_64 | Arch::S390x | Arch::AArch64,
"`softfloat` ABI is only valid for x86, s390x, and aarch64 targets"
),
Arch::S390x => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on s390x");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on s390x");
check_matches!(
(&self.rustc_abi, &self.abi),
(Some(RustcAbi::Softfloat), Abi::SoftFloat)
| (None, Abi::Unspecified | Abi::Other(_)),
"invalid s390x Rust-specific ABI and `cfg(target_abi)` combination:\n\
Rust-specific ABI: {:?}\n\
cfg(target_abi): {}",
self.rustc_abi,
self.abi,
);
}
Arch::LoongArch32 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
check_matches!(
(&*self.llvm_abiname, &self.abi),
("ilp32s", Abi::SoftFloat)
| ("ilp32f", Abi::Unspecified | Abi::Other(_))
| ("ilp32d", Abi::Unspecified | Abi::Other(_)),
"invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::LoongArch64 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
check_matches!(
(&*self.llvm_abiname, &self.abi),
("lp64s", Abi::SoftFloat)
| ("lp64f", Abi::Unspecified | Abi::Other(_))
| ("lp64d", Abi::Unspecified | Abi::Other(_)),
"invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::Mips | Arch::Mips32r6 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
check_matches!(
(&*self.llvm_abiname, &self.abi),
("o32", Abi::Unspecified | Abi::Other(_)),
"invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::Mips64 | Arch::Mips64r6 => {
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
check_matches!(
(&*self.llvm_abiname, &self.abi),
// No in-tree targets use "n32" but at least for now we let out-of-tree targets
// experiment with that.
("n64", Abi::Abi64) | ("n32", Abi::Unspecified | Abi::Other(_)),
"invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
ABI name: {}\n\
cfg(target_abi): {}",
self.llvm_abiname,
self.abi,
);
}
Arch::CSky => {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on CSky");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on CSky");
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on CSky");
// FIXME: Check that `target_abi` matches the actually configured ABI (v2 vs v2hf).
check_matches!(
self.abi,
Abi::AbiV2 | Abi::AbiV2Hf,
"invalid `target_abi` for CSky"
);
}
ref arch => {
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on {arch}");
// Ensure consistency among built-in targets, but give JSON targets the opportunity
// to experiment with these.
if kind == TargetKind::Builtin {
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on {arch}");
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on {arch}");
check_matches!(
self.abi,
Abi::Unspecified | Abi::Other(_),
"`target_abi` is unused on {arch}"
);
}
}
}
@@ -3305,7 +3513,8 @@ fn test_target(mut self) {
let recycled_target =
Target::from_json(&serde_json::to_string(&self.to_json()).unwrap()).map(|(j, _)| j);
self.update_to_cli();
self.check_consistency(TargetKind::Builtin).unwrap();
self.check_consistency(TargetKind::Builtin)
.unwrap_or_else(|err| panic!("Target consistency check failed:\n{err}"));
assert_eq!(recycled_target, Ok(self));
}
@@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
endian: Endian::Big,
cpu: "mips32r2".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
features: "+mips32r2,+soft-float,+noabicalls".into(),
@@ -18,6 +18,7 @@ pub(crate) fn target() -> Target {
endian: Endian::Big,
cpu: "mips32r2".into(),
features: "+mips32r2,+fpxx,+nooddspreg".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
@@ -18,6 +18,11 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
arch: Arch::Mips,
options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
options: TargetOptions {
endian: Endian::Big,
llvm_abiname: "o32".into(),
mcount: "_mcount".into(),
..base
},
}
}
@@ -18,6 +18,7 @@ pub(crate) fn target() -> Target {
endian: Endian::Big,
cpu: "mips32r2".into(),
features: "+mips32r2,+soft-float".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
@@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
endian: Endian::Little,
cpu: "mips32r2".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
features: "+mips32r2,+soft-float,+noabicalls".into(),
@@ -36,6 +36,7 @@ pub(crate) fn target() -> Target {
// PSP does not support trap-on-condition instructions.
llvm_args: cvs!["-mno-check-zero-division"],
llvm_abiname: "o32".into(),
pre_link_args,
link_script: Some(LINKER_SCRIPT.into()),
..Default::default()
@@ -16,6 +16,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
cpu: "mips32r2".into(),
features: "+mips32r2,+fpxx,+nooddspreg".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
@@ -16,6 +16,6 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
arch: Arch::Mips,
options: TargetOptions { mcount: "_mcount".into(), ..base },
options: TargetOptions { llvm_abiname: "o32".into(), mcount: "_mcount".into(), ..base },
}
}
@@ -16,6 +16,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
cpu: "mips32r2".into(),
features: "+mips32r2,+soft-float".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
arch: Arch::Mips,
options: TargetOptions {
features: "+soft-float".into(),
llvm_abiname: "o32".into(),
mcount: "__mcount".into(),
endian: Endian::Little,
..base
@@ -23,6 +23,7 @@ pub(crate) fn target() -> Target {
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
cpu: "mips32r2".into(),
features: "+mips32r2,+soft-float,+noabicalls".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
linker: Some("rust-lld".into()),
panic_strategy: PanicStrategy::Abort,
@@ -18,6 +18,7 @@ pub(crate) fn target() -> Target {
endian: Endian::Big,
cpu: "mips32r6".into(),
features: "+mips32r6".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
@@ -16,6 +16,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
cpu: "mips32r6".into(),
features: "+mips32r6".into(),
llvm_abiname: "o32".into(),
max_atomic_width: Some(32),
mcount: "_mcount".into(),
+39
View File
@@ -88,6 +88,45 @@
//@ lldb-command: frame select
//@ lldb-check: [...]let m: *const() = &a;[...]
// === CDB TESTS ===================================================================================
// Enable source line support. See
// https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/-lines--toggle-source-line-support-.
//@ cdb-command: .lines -e
// Display source lines and source line numbers at the command prompt. See
// https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/l---l---set-source-options-.
//@ cdb-command: l+s
// Enter "source mode" so `p` steps source lines and not assembly instructions.
//@ cdb-command: l+t
// `g` means "go". See
// https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/g--go-.
//@ cdb-command: g
// `p` means "step". See
// https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/p--step-.
//@ cdb-command: p
//@ cdb-check: [...]: let mut c = 27;
//@ cdb-command: p
//@ cdb-check: [...]: let d = c = 99;
//@ [no-SingleUseConsts-mir-pass] cdb-command: p
//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let e = "hi bob";
//@ [no-SingleUseConsts-mir-pass] cdb-command: p
//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let f = b"hi bob";
//@ [no-SingleUseConsts-mir-pass] cdb-command: p
//@ [no-SingleUseConsts-mir-pass] cdb-check: [...]: let g = b'9';
//@ cdb-command: p
//@ cdb-check: [...]: let h = ["whatever"; 8];
//@ cdb-command: p
//@ cdb-check: [...]: let i = [1,2,3,4];
//@ cdb-command: p
//@ cdb-check: [...]: let j = (23, "hi");
//@ cdb-command: p
//@ cdb-check: [...]: let k = 2..3;
//@ cdb-command: p
//@ cdb-check: [...]: let l = &i[k];
//@ cdb-command: p
//@ cdb-check: [...]: let m: *const() = &a;
#![allow(unused_assignments, unused_variables)]
fn main () {
-10
View File
@@ -1000,12 +1000,6 @@ Tests on lifetimes on objects, such as a lifetime bound not being able to be ded
**FIXME**: Just a more specific subset of `ui/lifetimes`.
## `tests/ui/obsolete-in-place/`
Contains a single test. Check that we reject the ancient Rust syntax `x <- y` and `in(BINDING) {}` construct.
**FIXME**: Definitely should be rehomed, maybe to `tests/ui/deprecation/`.
## `tests/ui/offload`
Exercises the offload feature.
@@ -1023,10 +1017,6 @@ Exercises the [`std::mem::offset_of` macro](https://doc.rust-lang.org/beta/std/m
Exercises the `#[rustc_on_unimplemented]`.
## `tests/ui/operator-recovery/`
**FIXME**: Probably move under `tests/ui/binop/` or `tests/ui/parser/`.
## `tests/ui/or-patterns/`
Exercises `||` and `|` in patterns.
@@ -1,5 +1,5 @@
error: unexpected token: `<-`
--> $DIR/bad.rs:5:7
--> $DIR/removed-syntax-obsolete-in-place.rs:5:7
|
LL | x <- y;
| ^^
@@ -10,7 +10,7 @@ LL | x < - y;
| +
error: expected expression, found keyword `in`
--> $DIR/bad.rs:10:5
--> $DIR/removed-syntax-obsolete-in-place.rs:10:5
|
LL | in(foo) { bar };
| ^^ expected expression