diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 97dd21db07e7d..0785942d13a38 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -287,10 +287,9 @@ impl TypedArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = ArenaChunk::::new(new_cap); + let chunk = chunks.push_mut(ArenaChunk::::new(new_cap)); self.ptr.set(chunk.start()); self.end.set(chunk.end()); - chunks.push(chunk); } } @@ -419,7 +418,7 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE)); + let chunk = chunks.push_mut(ArenaChunk::new(align_up(new_cap, PAGE))); self.start.set(chunk.start()); // Align the end to DROPLESS_ALIGNMENT. @@ -430,8 +429,6 @@ impl DroplessArena { debug_assert!(chunk.start().addr() <= end); self.end.set(chunk.end().with_addr(end)); - - chunks.push(chunk); } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a42d4e0d05557..47c933e245d49 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -743,7 +743,7 @@ impl SourceMap { let n = s[..start] .char_indices() .rfind(|&(_, c)| !f(c)) - .map_or(start, |(i, _)| start - i - 1); + .map_or(start, |(i, c)| start - i - c.len_utf8()); Ok(span.with_lo(span.lo() - BytePos(n as u32))) }) } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 161bb31c664e7..c0679c9552dfa 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -477,6 +477,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start + ("audio", Unstable(sym::hexagon_target_feature), &[]), ("hvx", Unstable(sym::hexagon_target_feature), &[]), ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]), ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]), @@ -493,6 +494,17 @@ const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]), ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]), ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]), + ("v60", Unstable(sym::hexagon_target_feature), &[]), + ("v62", Unstable(sym::hexagon_target_feature), &["v60"]), + ("v65", Unstable(sym::hexagon_target_feature), &["v62"]), + ("v66", Unstable(sym::hexagon_target_feature), &["v65"]), + ("v67", Unstable(sym::hexagon_target_feature), &["v66"]), + ("v68", Unstable(sym::hexagon_target_feature), &["v67"]), + ("v69", Unstable(sym::hexagon_target_feature), &["v68"]), + ("v71", Unstable(sym::hexagon_target_feature), &["v69"]), + ("v73", Unstable(sym::hexagon_target_feature), &["v71"]), + ("v75", Unstable(sym::hexagon_target_feature), &["v73"]), + ("v79", Unstable(sym::hexagon_target_feature), &["v75"]), ("zreg", Unstable(sym::hexagon_target_feature), &[]), // tidy-alphabetical-end ]; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 5e7a59bd7ae8e..43ab4a64fbedc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -874,7 +874,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if let Ok(Some(ImplSource::UserDefined(impl_data))) = - SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref.skip_binder())) + self.enter_forall(trait_ref, |trait_ref_for_select| { + SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref_for_select)) + }) { let impl_did = impl_data.impl_def_id; let trait_did = trait_ref.def_id(); diff --git a/library/proc_macro/src/bridge/arena.rs b/library/proc_macro/src/bridge/arena.rs index 5e0393e98fdd2..d4879021f9d87 100644 --- a/library/proc_macro/src/bridge/arena.rs +++ b/library/proc_macro/src/bridge/arena.rs @@ -58,11 +58,10 @@ impl Arena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = Box::new_uninit_slice(new_cap); + let chunk = chunks.push_mut(Box::new_uninit_slice(new_cap)); let Range { start, end } = chunk.as_mut_ptr_range(); self.start.set(start); self.end.set(end); - chunks.push(chunk); } /// Allocates a byte slice with specified size from the current memory diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs index 4fc3ce94fb8be..04a8e6854fc08 100644 --- a/src/tools/miri/genmc-sys/build.rs +++ b/src/tools/miri/genmc-sys/build.rs @@ -31,8 +31,8 @@ mod downloading { pub(crate) const GENMC_COMMIT: &str = "22d3d0b44dedb4e8e1aae3330e546465e4664529"; /// Ensure that a local GenMC repo is present and set to the correct commit. - /// Return the path of the GenMC repo and whether the checked out commit was changed. - pub(crate) fn download_genmc() -> (PathBuf, bool) { + /// Return the path of the GenMC repo clone. + pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); let commit_oid = Oid::from_str(GENMC_COMMIT).expect("Commit should be valid."); @@ -44,7 +44,7 @@ mod downloading { && head_commit.id() == commit_oid { // Fast path: The expected commit is already checked out. - return (genmc_download_path, false); + return genmc_download_path; } // Check if the local repository already contains the commit we need, download it otherwise. let commit = update_local_repo(&repo, commit_oid); @@ -61,7 +61,7 @@ mod downloading { } }; - (genmc_download_path, true) + genmc_download_path } fn get_remote(repo: &Repository) -> Remote<'_> { @@ -141,7 +141,7 @@ mod downloading { } /// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs -fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) { +fn compile_cpp_dependencies(genmc_path: &Path) { // Give each step a separate build directory to prevent interference. let out_dir = PathBuf::from(std::env::var("OUT_DIR").as_deref().unwrap()); let genmc_build_dir = out_dir.join("genmc"); @@ -156,7 +156,6 @@ fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) { let mut config = cmake::Config::new(genmc_path); config - .always_configure(always_configure) // We force running the configure step when the GenMC commit changed. .out_dir(genmc_build_dir) .profile(GENMC_CMAKE_PROFILE) .define("BUILD_LLI", "OFF") @@ -208,8 +207,7 @@ fn main() { } // Select which path to use for the GenMC repo: - let (genmc_path, always_configure) = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") - { + let genmc_path = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") { let genmc_src_path = PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path"); assert!( @@ -219,18 +217,14 @@ fn main() { ); // Rebuild files in the given path change. println!("cargo::rerun-if-changed={}", genmc_src_path.display()); - // We disable `always_configure` when working with a local repository, - // since it increases compile times when working on `genmc-sys`. - (genmc_src_path, false) + genmc_src_path } else { // Download GenMC if required and ensure that the correct commit is checked out. - // If anything changed in the downloaded repository (e.g., the commit), - // we set `always_configure` to ensure there are no weird configs from previous builds. downloading::download_genmc() }; // Build all required components: - compile_cpp_dependencies(&genmc_path, always_configure); + compile_cpp_dependencies(&genmc_path); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index af66f0a4d9eab..38f153f78d026 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -55e86c996809902e8bbad512cfb4d2c18be446d9 +4c4205163abcbd08948b3efab796c543ba1ea687 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 36cf640cb8449..bb52bde6fe7b2 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -309,8 +309,9 @@ impl rustc_driver::Callbacks for MiriDepCompilerCalls { // We need to add #[used] symbols to exported_symbols for `lookup_link_section`. // FIXME handle this somehow in rustc itself to avoid this hack. local_providers.queries.exported_non_generic_symbols = |tcx, LocalCrate| { - let reachable_set = tcx - .with_stable_hashing_context(|mut hcx| tcx.reachable_set(()).to_sorted(&mut hcx, true)); + let reachable_set = tcx.with_stable_hashing_context(|mut hcx| { + tcx.reachable_set(()).to_sorted(&mut hcx, true) + }); tcx.arena.alloc_from_iter( // This is based on: // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs index 13846710615eb..479338788b5ff 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs @@ -7,9 +7,9 @@ use crate::borrow_tracker::BorTag; pub struct Item(u64); // An Item contains 3 bitfields: -// * Bits 0-61 store a BorTag. -// * Bits 61-63 store a Permission. -// * Bit 64 stores a flag which indicates if we might have a protector. +// * Bits 0-60 store a BorTag (61 bits). +// * Bits 61-62 store a Permission (2 bits). +// * Bit 63 stores a flag which indicates if we might have a protector (1 bit). // This is purely an optimization: if the bit is set, the tag *might* be // in `protected_tags`, but if the bit is not set then the tag is definitely // not in `protected_tags`. diff --git a/src/tools/miri/src/concurrency/blocking_io.rs b/src/tools/miri/src/concurrency/blocking_io.rs index 221d0495cd162..ba1e52cd39712 100644 --- a/src/tools/miri/src/concurrency/blocking_io.rs +++ b/src/tools/miri/src/concurrency/blocking_io.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::io; use std::time::Duration; @@ -5,6 +6,7 @@ use mio::event::Source; use mio::{Events, Interest, Poll, Token}; use rustc_data_structures::fx::FxHashMap; +use crate::shims::{FdId, FileDescriptionRef}; use crate::*; /// Capacity of the event queue which can be polled at a time. @@ -18,6 +20,14 @@ pub trait WithSource { fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()>; } +/// An interest receiver defines the action that should be taken when +/// the associated [`Interest`] is fulfilled. +#[derive(Debug, Hash, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +pub enum InterestReceiver { + /// The specified thread should be unblocked. + UnblockThread(ThreadId), +} + /// Manager for managing blocking host I/O in a non-blocking manner. /// We use [`Poll`] to poll for new I/O events from the OS for sources /// registered using this manager. @@ -34,9 +44,10 @@ pub struct BlockingIoManager { /// This is not part of the state and only stored to avoid allocating a /// new buffer for every poll. events: Events, - /// Map between threads which are currently blocked and the - /// underlying I/O source. - sources: FxHashMap>, + /// Map from source ids to the actual sources and their registered receivers + /// together with their associated interests. + sources: + BTreeMap, FxHashMap)>, } impl BlockingIoManager { @@ -46,7 +57,7 @@ impl BlockingIoManager { let manager = Self { poll: communicate.then_some(Poll::new()?), events: Events::with_capacity(IO_EVENT_CAPACITY), - sources: FxHashMap::default(), + sources: BTreeMap::default(), }; Ok(manager) } @@ -59,8 +70,12 @@ impl BlockingIoManager { /// specified duration. /// - If the timeout is [`None`] the poll blocks indefinitely until an event occurs. /// - /// Returns all threads that are ready because they received an I/O event. - pub fn poll(&mut self, timeout: Option) -> Result, io::Error> { + /// Returns the interest receivers for all file descriptions which received an I/O event together + /// with the file description they were registered for. + pub fn poll( + &mut self, + timeout: Option, + ) -> Result)>, io::Error> { let poll = self.poll.as_mut().expect("Blocking I/O should not be called with isolation enabled"); @@ -70,56 +85,120 @@ impl BlockingIoManager { let ready = self .events .iter() - .map(|event| { + .flat_map(|event| { let token = event.token(); - ThreadId::new_unchecked(token.0.try_into().unwrap()) + // We know all tokens are valid `FdId`. + let fd_id = FdId::new_unchecked(token.0); + let (source, interests) = + self.sources.get(&fd_id).expect("Source should be registered"); + assert_eq!(source.id(), fd_id); + // Because we allow spurious wake-ups, we mark all interests as ready even + // though some may not have been fulfilled. + interests.keys().map(move |receiver| (*receiver, source.clone())) }) .collect::>(); - // Deregister all ready sources as we only want to receive one event per thread. - ready.iter().for_each(|thread_id| self.deregister(*thread_id)); + // Deregister all ready sources as we only want to receive one event per receiver. + ready.iter().for_each(|(receiver, source)| self.deregister(source.id(), *receiver)); Ok(ready) } - /// Register a blocking I/O source for a thread together with it's poll interests. - /// - /// The source will be deregistered automatically once an event for it is received. + /// Register an interest for a blocking I/O source. /// /// As the OS can always produce spurious wake-ups, it's the callers responsibility to /// verify the requested I/O interests are really ready and to register again if they're not. - pub fn register(&mut self, source: Box, thread: ThreadId, interests: Interest) { + /// + /// It's assumed that no interest is already registered for this source with the same reason! + pub fn register( + &mut self, + source_fd: FileDescriptionRef, + receiver: InterestReceiver, + interest: Interest, + ) { let poll = self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled"); - let token = Token(thread.to_u32().to_usize()); + let id = source_fd.id(); + let token = Token(id.to_usize()); + + let Some((_, current_interests)) = self.sources.get_mut(&id) else { + // The source is not yet registered. + + // Treat errors from registering as fatal. On UNIX hosts this can only + // fail due to system resource errors (e.g. ENOMEM or ENOSPC). + source_fd + .with_source(&mut |source| poll.registry().register(source, token, interest)) + .unwrap(); + + self.sources.insert(id, (source_fd, FxHashMap::from_iter([(receiver, interest)]))); + return; + }; + + // The source is already registered. We need to check whether we need to + // reregister because the provided interest contains new interests for the source. - // Treat errors from registering as fatal. On UNIX hosts this can only + let old_interest = + interest_union(current_interests).expect("Source should contain at least one interest"); + + current_interests + .try_insert(receiver, interest) + .unwrap_or_else(|_| panic!("Receiver should be unique")); + + let new_interest = old_interest.add(interest); + + // Reregister the source since the overall interests might have changed. + + // Treat errors from reregistering as fatal. On UNIX hosts this can only // fail due to system resource errors (e.g. ENOMEM or ENOSPC). - source - .with_source(&mut |source| source.register(poll.registry(), token, interests)) + source_fd + .with_source(&mut |source| poll.registry().reregister(source, token, new_interest)) .unwrap(); - self.sources - .try_insert(thread, source) - .unwrap_or_else(|_| panic!("A thread cannot be registered twice at the same time")); } - /// Deregister the event source for a thread. Returns the kind of I/O the thread was - /// blocked on. - fn deregister(&mut self, thread: ThreadId) { + /// Deregister an interest from a blocking I/O source. + /// + /// The receiver is assumed to be registered for the provided source! + pub fn deregister(&mut self, source_id: FdId, receiver: InterestReceiver) { let poll = self.poll.as_ref().expect("Blocking I/O should not be called with isolation enabled"); - let Some(source) = self.sources.remove(&thread) else { - panic!("Attempt to deregister a token which isn't registered") + let token = Token(source_id.to_usize()); + let (fd, current_interests) = + self.sources.get_mut(&source_id).expect("Source should be registered"); + + current_interests + .remove(&receiver) + .unwrap_or_else(|| panic!("Receiver should be registered for source")); + + let Some(new_interest) = interest_union(current_interests) else { + // There are no longer any interests in this source. + // We can thus deregister the source from the poll. + + // Treat errors from deregistering as fatal. On UNIX hosts this can only + // fail due to system resource errors (e.g. ENOMEM or ENOSPC). + fd.with_source(&mut |source| poll.registry().deregister(source)).unwrap(); + self.sources.remove(&source_id); + return; }; - // Treat errors from deregistering as fatal. On UNIX hosts this can only + // Reregister the source since the overall interests might have changed. + + // Treat errors from reregistering as fatal. On UNIX hosts this can only // fail due to system resource errors (e.g. ENOMEM or ENOSPC). - source.with_source(&mut |source| source.deregister(poll.registry())).unwrap(); + fd.with_source(&mut |source| poll.registry().reregister(source, token, new_interest)) + .unwrap(); } } +/// Get the union of all interests for a source. Returns `None` if the map is empty. +fn interest_union(interests: &FxHashMap) -> Option { + interests + .values() + .copied() + .fold(None, |acc, interest| acc.map(|acc: Interest| acc.add(interest)).or(Some(interest))) +} + impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Block the current thread until some interests on an I/O source @@ -132,15 +211,15 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn block_thread_for_io( &mut self, - source: impl WithSource + 'static, + source_fd: FileDescriptionRef, interests: Interest, timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, callback: DynUnblockCallback<'tcx>, ) { let this = self.eval_context_mut(); this.machine.blocking_io.register( - Box::new(source), - this.machine.threads.active_thread(), + source_fd, + InterestReceiver::UnblockThread(this.machine.threads.active_thread()), interests, ); this.block_thread(BlockReason::IO, timeout, callback); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index ee74e06815945..e9458cc3f4568 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -18,6 +18,7 @@ use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::Os; use crate::concurrency::GlobalDataRaceHandler; +use crate::concurrency::blocking_io::InterestReceiver; use crate::shims::tls; use crate::*; @@ -822,7 +823,12 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { Err(e) => panic!("unexpected error while polling: {e}"), }; - ready.into_iter().try_for_each(|thread_id| this.unblock_thread(thread_id, BlockReason::IO)) + ready.into_iter().try_for_each(|(receiver, _source)| { + match receiver { + InterestReceiver::UnblockThread(thread_id) => + this.unblock_thread(thread_id, BlockReason::IO), + } + }) } /// Find all threads with expired timeouts, unblock them and execute their timeout callbacks. diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 29088ed67135a..5468fd3037425 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -19,6 +19,17 @@ use crate::*; #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)] pub struct FdId(usize); +impl FdId { + pub fn to_usize(self) -> usize { + self.0 + } + + /// Create a new fd id from a `usize` without checking if this fd exists. + pub fn new_unchecked(id: usize) -> Self { + Self(id) + } +} + #[derive(Debug, Clone)] struct FdIdWith { id: FdId, diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 281dfc758f4e7..e15134fa01bb0 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -23,7 +23,7 @@ pub mod time; pub mod tls; pub mod unwind; -pub use self::files::FdTable; +pub use self::files::{FdId, FdTable, FileDescriptionRef}; #[cfg(all(feature = "native-lib", unix))] pub use self::native_lib::trace::{init_sv, register_retcode_sv}; pub use self::unix::{DirTable, EpollInterestTable}; diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 460015d4c3ccc..065f040cd3e1d 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -15,7 +15,7 @@ use crate::shims::unix::*; use crate::*; #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub(crate) enum FlockOp { +pub enum FlockOp { SharedLock { nonblocking: bool }, ExclusiveLock { nonblocking: bool }, Unlock, diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index bbdf6fc54b2cf..41a510cfe9b85 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -1388,7 +1388,7 @@ impl VisitProvenance for FileDescriptionRef { fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {} } -impl WithSource for FileDescriptionRef { +impl WithSource for Socket { fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()> { let mut state = self.state.borrow_mut(); match &mut *state { diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs index 7a4e038fabf79..f70ed0cbab8a8 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs @@ -10,13 +10,6 @@ use std::sync::atomic::*; use std::thread::spawn; -#[allow(dead_code)] -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - // We can't create static items because we need to run each test multiple times. fn static_uninit_atomic() -> &'static AtomicUsize { unsafe { Box::leak(Box::new_uninit()).assume_init_ref() } diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs index 4955dfd8a77ad..fc522dd013fa1 100644 --- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs @@ -29,10 +29,6 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { let x = AtomicUsize::new(0); let y = AtomicUsize::new(0); - // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. - x.store(0, Relaxed); - y.store(0, Relaxed); - let mut a: usize = 1234; let mut b: usize = 1234; unsafe { diff --git a/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs b/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs new file mode 100644 index 0000000000000..d4bae144f2213 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-blocking-io-same-fd.rs @@ -0,0 +1,56 @@ +//@ignore-target: windows # No libc socket on Windows +//@compile-flags: -Zmiri-disable-isolation -Zmiri-fixed-schedule + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use std::thread; + +use libc_utils::*; + +// This tests that the blocking I/O implementation works when multiple threads block on the +// same fd at the same time. + +fn main() { + let (server_sockfd, addr) = net::make_listener_ipv4(0).unwrap(); + let client_sockfd = + unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; + + // Spawn the server thread. + let server_thread = thread::spawn(move || { + let (peerfd, _) = net::accept_ipv4(server_sockfd).unwrap(); + + // Yield back to reader threads to ensure that we have + // two threads being blocked on the same fd at the same time. + thread::yield_now(); + + let mut buffer = [22u8; 128]; + let bytes_written = unsafe { + errno_result(net::send_all(peerfd, buffer.as_mut_ptr().cast(), buffer.len(), 0)) + .unwrap() + }; + assert_eq!(bytes_written as usize, 128); + }); + + net::connect_ipv4(client_sockfd, addr); + + let reader_thread = thread::spawn(move || { + let mut buffer = [0u8; 8]; + let bytes_read = unsafe { + errno_result(net::recv_all(client_sockfd, buffer.as_mut_ptr().cast(), buffer.len(), 0)) + .unwrap() + }; + assert_eq!(bytes_read, 8); + assert_eq!(&buffer, &[22u8; 8]); + }); + + let mut buffer = [0u8; 8]; + let bytes_read = unsafe { + errno_result(net::recv_all(client_sockfd, buffer.as_mut_ptr().cast(), buffer.len(), 0)) + .unwrap() + }; + assert_eq!(bytes_read, 8); + assert_eq!(&buffer, &[22u8; 8]); + + reader_thread.join().unwrap(); + server_thread.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 8961693f32393..e57bbeb938198 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -22,6 +22,10 @@ use std::hint::black_box; mod utils; use utils::check_nondet; +/// Error tolerance in ULP. +/// Miri adds 4 ULP of errors itself, and we allow for 4 additional ULP of host float error. +const ERR_TOLERANCE: i32 = 8; + /// Compare the two floats, allowing for $ulp many ULPs of error. /// /// ULP means "Units in the Last Place" or "Units of Least Precision". @@ -33,7 +37,7 @@ use utils::check_nondet; /// have a large value difference, their ULP can still be 1, so they are still "approximatly equal", /// but the EPSILON check would have failed. macro_rules! assert_approx_eq { - ($a:expr, $b:expr, $ulp:expr) => {{ + ($a:expr, $b:expr, $ulp:expr $( , )?) => {{ let (actual, expected) = ($a, $b); let allowed_ulp_diff = $ulp; let _force_same_type = actual == expected; @@ -46,9 +50,10 @@ macro_rules! assert_approx_eq { }; }}; - ($a:expr, $b: expr) => { - // accept up to 8ULP (4ULP for host floats and 4ULP for miri artificial error). - assert_approx_eq!($a, $b, 8); + ($a:expr, $b: expr $( , )?) => { + // Accept up to 12ULP (4ULP for miri artificial error and the rest for host floats). + // We saw failures on an i686-linux host with a limit of 8! + assert_approx_eq!($a, $b, ERR_TOLERANCE); }; } @@ -1195,10 +1200,10 @@ fn libm() { assert_approx_eq!(f16_consts::FRAC_PI_6.sin(), 0.5); assert_approx_eq!(f32_consts::FRAC_PI_6.sin(), 0.5); assert_approx_eq!(f64_consts::FRAC_PI_6.sin(), 0.5); - // Increase error tolerance to 16ULP because of the extra operation. - assert_approx_eq!(f16_consts::FRAC_PI_4.sin().asin(), f16_consts::FRAC_PI_4, 16); - assert_approx_eq!(f32_consts::FRAC_PI_4.sin().asin(), f32_consts::FRAC_PI_4, 16); - assert_approx_eq!(f64_consts::FRAC_PI_4.sin().asin(), f64_consts::FRAC_PI_4, 16); + // Increase error tolerance because of the extra operation. + assert_approx_eq!(f16_consts::FRAC_PI_4.sin().asin(), f16_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); + assert_approx_eq!(f32_consts::FRAC_PI_4.sin().asin(), f32_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); + assert_approx_eq!(f64_consts::FRAC_PI_4.sin().asin(), f64_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); assert_biteq(0.0f16.asin(), 0.0f16, "asin(+0) = +0"); assert_biteq((-0.0f16).asin(), -0.0, "asin(-0) = -0"); assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0"); @@ -1238,10 +1243,10 @@ fn libm() { assert_approx_eq!(f16_consts::FRAC_PI_3.cos(), 0.5); assert_approx_eq!(f32_consts::FRAC_PI_3.cos(), 0.5); assert_approx_eq!(f64_consts::FRAC_PI_3.cos(), 0.5); - // Increase error tolerance to 16ULP because of the extra operation. - assert_approx_eq!(f16_consts::FRAC_PI_4.cos().acos(), f16_consts::FRAC_PI_4, 16); - assert_approx_eq!(f32_consts::FRAC_PI_4.cos().acos(), f32_consts::FRAC_PI_4, 16); - assert_approx_eq!(f64_consts::FRAC_PI_4.cos().acos(), f64_consts::FRAC_PI_4, 16); + // Increase error tolerance because of the extra operation. + assert_approx_eq!(f16_consts::FRAC_PI_4.cos().acos(), f16_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); + assert_approx_eq!(f32_consts::FRAC_PI_4.cos().acos(), f32_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); + assert_approx_eq!(f64_consts::FRAC_PI_4.cos().acos(), f64_consts::FRAC_PI_4, 2 * ERR_TOLERANCE); assert_biteq(1.0f16.acos(), 0.0, "acos(1) = 0"); assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0"); assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0"); @@ -1262,9 +1267,10 @@ fn libm() { assert_approx_eq!(1.0f16.tan(), 1.557408f16); assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.5574077246549023f64); - assert_approx_eq!(1.0_f16, 1.0_f16.tan().atan()); - assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); - assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + // Increase error tolerance because of the extra operation. + assert_approx_eq!(1.0_f16, 1.0_f16.tan().atan(), 2 * ERR_TOLERANCE); + assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan(), 2 * ERR_TOLERANCE); + assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan(), 2 * ERR_TOLERANCE); assert_approx_eq!(1.0f16.atan2(2.0f16), 0.46364761f16); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); @@ -1315,17 +1321,21 @@ fn libm() { fixed_atan2_cases!(f32); fixed_atan2_cases!(f64); + // Imprecise operations on both sides needs higher error tolerance. assert_approx_eq!( 1.0f16.tanh(), - (1.0 - f16_consts::E.powi(-2)) / (1.0 + f16_consts::E.powi(-2)) + (1.0 - f16_consts::E.powi(-2)) / (1.0 + f16_consts::E.powi(-2)), + 2 * ERR_TOLERANCE, ); assert_approx_eq!( 1.0f32.tanh(), - (1.0 - f32_consts::E.powi(-2)) / (1.0 + f32_consts::E.powi(-2)) + (1.0 - f32_consts::E.powi(-2)) / (1.0 + f32_consts::E.powi(-2)), + 2 * ERR_TOLERANCE, ); assert_approx_eq!( 1.0f64.tanh(), - (1.0 - f64_consts::E.powi(-2)) / (1.0 + f64_consts::E.powi(-2)) + (1.0 - f64_consts::E.powi(-2)) / (1.0 + f64_consts::E.powi(-2)), + 2 * ERR_TOLERANCE, ); assert_eq!(f16::INFINITY.tanh(), 1.0); assert_eq!(f16::NEG_INFINITY.tanh(), -1.0); @@ -1348,15 +1358,16 @@ fn libm() { assert_eq!(2.0f16.ln_gamma(), (0.0, 1)); assert_eq!(2.0f32.ln_gamma(), (0.0, 1)); assert_eq!(2.0f64.ln_gamma(), (0.0, 1)); - // Gamma(-0.5) = -2*sqrt(π) + // Gamma(-0.5) = -2*sqrt(π), then apply `ln` on both sides. + // This has imprecise float ops on both sides so we double the error tolerance. let (val, sign) = (-0.5f16).ln_gamma(); - assert_approx_eq!(val, (2.0 * f16_consts::PI.sqrt()).ln()); + assert_approx_eq!(val, (2.0 * f16_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE); assert_eq!(sign, -1); let (val, sign) = (-0.5f32).ln_gamma(); - assert_approx_eq!(val, (2.0 * f32_consts::PI.sqrt()).ln()); + assert_approx_eq!(val, (2.0 * f32_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE); assert_eq!(sign, -1); let (val, sign) = (-0.5f64).ln_gamma(); - assert_approx_eq!(val, (2.0 * f64_consts::PI.sqrt()).ln()); + assert_approx_eq!(val, (2.0 * f64_consts::PI.sqrt()).ln(), 2 * ERR_TOLERANCE); assert_eq!(sign, -1); assert_approx_eq!(1.0f16.erf(), 0.84270079294971486934122063508260926f16); diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 06384c2202f1e..343b894405e97 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -31,6 +31,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `amx-tile` `apxf` `atomics` +`audio` `avx` `avx10.1` `avx10.2` @@ -359,9 +360,20 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `v` `v5te` `v6` +`v60` +`v62` +`v65` +`v66` +`v67` +`v68` +`v69` `v6k` `v6t2` `v7` +`v71` +`v73` +`v75` +`v79` `v8` `v8.1a` `v8.2a` diff --git a/tests/ui/span/span-extend-prev-while-multibyte.rs b/tests/ui/span/span-extend-prev-while-multibyte.rs new file mode 100644 index 0000000000000..292699d6aa3ea --- /dev/null +++ b/tests/ui/span/span-extend-prev-while-multibyte.rs @@ -0,0 +1,10 @@ +//@ build-pass +// Regression test for https://github.com/rust-lang/rust/issues/155037 +#![feature(associated_type_defaults)] + +trait Trait { + type 否 where = (); + //~^ WARNING where clause not allowed here +} + +fn main() {} diff --git a/tests/ui/span/span-extend-prev-while-multibyte.stderr b/tests/ui/span/span-extend-prev-while-multibyte.stderr new file mode 100644 index 0000000000000..20232baa992bf --- /dev/null +++ b/tests/ui/span/span-extend-prev-while-multibyte.stderr @@ -0,0 +1,16 @@ +warning: where clause not allowed here + --> $DIR/span-extend-prev-while-multibyte.rs:6:12 + | +LL | type 否 where = (); + | ^^^^^ + | + = note: see issue #89122 for more information + = note: `#[warn(deprecated_where_clause_location)]` on by default +help: move it to the end of the type declaration + | +LL - type 否 where = (); +LL + type 否 = () where; + | + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr new file mode 100644 index 0000000000000..99a6aa67e7feb --- /dev/null +++ b/tests/ui/target-feature/feature-hierarchy.hexagon-hvxv66.stderr @@ -0,0 +1,6 @@ +warning: unstable feature specified for `-Ctarget-feature`: `hvxv66` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr new file mode 100644 index 0000000000000..611bf370bdfa7 --- /dev/null +++ b/tests/ui/target-feature/feature-hierarchy.hexagon-v60.stderr @@ -0,0 +1,6 @@ +warning: unstable feature specified for `-Ctarget-feature`: `v60` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr b/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr new file mode 100644 index 0000000000000..67343fa798b83 --- /dev/null +++ b/tests/ui/target-feature/feature-hierarchy.hexagon-v68.stderr @@ -0,0 +1,6 @@ +warning: unstable feature specified for `-Ctarget-feature`: `v68` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index a14af97d7234b..65f7a1e6d3db4 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -1,14 +1,22 @@ //@ revisions: aarch64-neon aarch64-sve2 +//@ revisions: hexagon-v60 hexagon-v68 hexagon-hvxv66 //@ [aarch64-neon] compile-flags: -Ctarget-feature=+neon --target=aarch64-unknown-linux-gnu //@ [aarch64-neon] needs-llvm-components: aarch64 //@ [aarch64-sve2] compile-flags: -Ctarget-feature=-neon,+sve2 --target=aarch64-unknown-linux-gnu //@ [aarch64-sve2] needs-llvm-components: aarch64 +//@ [hexagon-v60] compile-flags: -Ctarget-feature=+v60 --target=hexagon-unknown-linux-musl +//@ [hexagon-v60] needs-llvm-components: hexagon +//@ [hexagon-v68] compile-flags: -Ctarget-feature=+v68 --target=hexagon-unknown-linux-musl +//@ [hexagon-v68] needs-llvm-components: hexagon +//@ [hexagon-hvxv66] compile-flags: -Ctarget-feature=+hvxv66 --target=hexagon-unknown-linux-musl +//@ [hexagon-hvxv66] needs-llvm-components: hexagon //@ build-pass //@ add-minicore //@ ignore-backends: gcc #![no_core] #![crate_type = "rlib"] #![feature(intrinsics, rustc_attrs, no_core, staged_api)] +#![cfg_attr(any(hexagon_v60, hexagon_v68, hexagon_hvxv66), feature(hexagon_target_feature))] #![stable(feature = "test", since = "1.0.0")] // Tests vetting "feature hierarchies" in the cases where we impose them. @@ -54,3 +62,39 @@ fn check_sve2_includes_neon() { assert!(cfg!(target_feature = "neon")); assert!(cfg!(target_feature = "sve2")); } + +//[hexagon-v60]~? WARN unstable feature specified for `-Ctarget-feature`: `v60` +//[hexagon-v68]~? WARN unstable feature specified for `-Ctarget-feature`: `v68` +//[hexagon-hvxv66]~? WARN unstable feature specified for `-Ctarget-feature`: `hvxv66` + +#[cfg(hexagon_v60)] +fn check_v60_not_v68() { + // Enabling v60 should not jump up the scalar feature hierarchy. + assert!(cfg!(target_feature = "v60")); + assert!(cfg!(not(target_feature = "v62"))); + assert!(cfg!(not(target_feature = "v68"))); +} + +#[cfg(hexagon_v68)] +fn check_v68_implies_v60() { + // v68 implies all lower scalar arch versions. + assert!(cfg!(target_feature = "v60")); + assert!(cfg!(target_feature = "v62")); + assert!(cfg!(target_feature = "v65")); + assert!(cfg!(target_feature = "v66")); + assert!(cfg!(target_feature = "v67")); + assert!(cfg!(target_feature = "v68")); + assert!(cfg!(not(target_feature = "v69"))); +} + +#[cfg(hexagon_hvxv66)] +fn check_hvxv66_implies_hvx_and_zreg() { + // hvxv66 implies hvx, hvxv60..v65, and zreg. + assert!(cfg!(target_feature = "hvx")); + assert!(cfg!(target_feature = "hvxv60")); + assert!(cfg!(target_feature = "hvxv62")); + assert!(cfg!(target_feature = "hvxv65")); + assert!(cfg!(target_feature = "hvxv66")); + assert!(cfg!(target_feature = "zreg")); + assert!(cfg!(not(target_feature = "hvxv67"))); +} diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs new file mode 100644 index 0000000000000..4185228a2586f --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.rs @@ -0,0 +1,12 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/151894 +//@ compile-flags: -Znext-solver=globally + +#![feature(const_trait_impl)] + +const fn with_positive [const] Fn(&'a ())>() {} + +const _: () = { + with_positive::<()>(); //~ ERROR expected a `Fn(&'a ())` closure, found `()` +}; + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr new file mode 100644 index 0000000000000..18f513cea6d49 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/const-host-effect-hrtb-no-ice.stderr @@ -0,0 +1,16 @@ +error[E0277]: expected a `Fn(&'a ())` closure, found `()` + --> $DIR/const-host-effect-hrtb-no-ice.rs:9:21 + | +LL | with_positive::<()>(); + | ^^ expected an `Fn(&'a ())` closure, found `()` + | + = help: the trait `for<'a> Fn(&'a ())` is not implemented for `()` +note: required by a bound in `with_positive` + --> $DIR/const-host-effect-hrtb-no-ice.rs:6:27 + | +LL | const fn with_positive [const] Fn(&'a ())>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `with_positive` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.