diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 01181ce261842..9b08f4e9869cf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -262,6 +262,11 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("crypto")), s => Some(LLVMFeature::new(s)), }, + Arch::RiscV32 | Arch::RiscV64 => match s { + // Filter out Rust-specific *virtual* target feature + "zkne_or_zknd" => None, + s => Some(LLVMFeature::new(s)), + }, Arch::Sparc | Arch::Sparc64 => match s { "leoncasa" => Some(LLVMFeature::new("hasleoncasa")), s => Some(LLVMFeature::new(s)), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index e5d66364c2a6e..9d8a84c52e980 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -271,6 +271,8 @@ declare_features! ( /// Allows `#[link(kind = "static-nobundle", ...)]`. (removed, static_nobundle, "1.63.0", Some(37403), Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818), + /// Allows string patterns to dereference values to match them. + (removed, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), Some("superseded by `deref_patterns`"), 150530), (removed, struct_inherit, "1.0.0", None, None), (removed, test_removed_feature, "1.0.0", None, None), /// Allows using items which are missing stability attributes diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 692cba8035c49..34b7cac5c941f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -647,8 +647,6 @@ declare_features! ( (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. (unstable, strict_provenance_lints, "1.61.0", Some(130351)), - /// Allows string patterns to dereference values to match them. - (unstable, string_deref_patterns, "1.67.0", Some(87121)), /// Allows `super let` statements. (unstable, super_let, "1.88.0", Some(139076)), /// Allows subtrait items to shadow supertrait items. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 1a579c4c6fa4a..90e22b2cd381a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -996,20 +996,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_ty = self.tcx.types.str_; } - if self.tcx.features().string_deref_patterns() - && let hir::PatExprKind::Lit { - lit: Spanned { node: ast::LitKind::Str(..), .. }, .. - } = lt.kind - { - let tcx = self.tcx; - let expected = self.resolve_vars_if_possible(expected); - pat_ty = match expected.kind() { - ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected, - ty::Str => Ty::new_static_str(tcx), - _ => pat_ty, - }; - } - // Somewhat surprising: in this case, the subtyping relation goes the // opposite way as the other cases. Actually what we really want is not // a subtyping relation at all but rather that there exists a LUB diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 65bfc7d362b61..3683c1cfb7ddb 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -827,7 +827,6 @@ pub enum PatKind<'tcx> { /// much simpler. /// * raw pointers derived from integers, other raw pointers will have already resulted in an /// error. - /// * `String`, if `string_deref_patterns` is enabled. Constant { value: ty::Value<'tcx>, }, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index cac4f7b7ab4f8..972d9f66faddc 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -150,7 +150,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut expect = self.literal_operand(test.span, Const::from_ty_value(tcx, value)); let mut place = place; - let mut block = block; + match cast_ty.kind() { ty::Str => { // String literal patterns may have type `str` if `deref_patterns` is @@ -175,34 +175,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place = ref_place; cast_ty = ref_str_ty; } - ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => { - if !tcx.features().string_deref_patterns() { - span_bug!( - test.span, - "matching on `String` went through without enabling string_deref_patterns" - ); - } - let re_erased = tcx.lifetimes.re_erased; - let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); - let ref_str = self.temp(ref_str_ty, test.span); - let eq_block = self.cfg.start_new_block(); - // `let ref_str: &str = ::deref(&place);` - self.call_deref( - block, - eq_block, - place, - Mutability::Not, - cast_ty, - ref_str, - test.span, - ); - // Since we generated a `ref_str = ::deref(&place) -> eq_block` terminator, - // we need to add all further statements to `eq_block`. - // Similarly, the normal test code should be generated for the `&str`, instead of the `String`. - block = eq_block; - place = ref_str; - cast_ty = ref_str_ty; - } &ty::Pat(base, _) => { assert_eq!(cast_ty, value.ty); assert!(base.is_trivially_pure_clone_copy()); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 063bb4a3d461a..0310003e7d58e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer}; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, LangItem, RangeEnd}; +use rustc_hir::{self as hir, RangeEnd}; use rustc_index::Idx; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::thir::{ @@ -626,23 +626,7 @@ impl<'tcx> PatCtxt<'tcx> { // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the // pattern's type means we'll properly translate it to a slice reference pattern. This works // because slices and arrays have the same valtree representation. - // HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if - // `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR. - // FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is - // superseded by a more general implementation of deref patterns. let ct_ty = match pat_ty { - Some(pat_ty) - if let ty::Adt(def, _) = *pat_ty.kind() - && self.tcx.is_lang_item(def.did(), LangItem::String) => - { - if !self.tcx.features().string_deref_patterns() { - span_bug!( - expr.span, - "matching on `String` went through without enabling string_deref_patterns" - ); - } - self.typeck_results.node_type(expr.hir_id) - } Some(pat_ty) => pat_ty, None => self.typeck_results.node_type(expr.hir_id), }; diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 2fd58d3334226..28d8e84137a29 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -690,8 +690,9 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zimop", Unstable(sym::riscv_target_feature), &[]), ("zk", Stable, &["zkn", "zkr", "zkt"]), ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), - ("zknd", Stable, &[]), - ("zkne", Stable, &[]), + ("zknd", Stable, &["zkne_or_zknd"]), + ("zkne", Stable, &["zkne_or_zknd"]), + ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension ("zknh", Stable, &[]), ("zkr", Stable, &[]), ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 9b600cd55758b..ad8608bf61908 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -48,7 +48,7 @@ impl Buffer { #[inline] pub fn buffer(&self) -> &[u8] { - // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and + // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and // that region is initialized because those are all invariants of this type. unsafe { self.buf.get_unchecked(self.pos..self.filled).assume_init_ref() } } diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index 5ebeada59bb53..967e24812b9ff 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -52,7 +52,7 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { } impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { - /// Writes some data into this BufReader with line buffering. + /// Writes some data into this BufWriter with line buffering. /// /// This means that, if any newlines are present in the data, the data up to /// the last newline is sent directly to the underlying writer, and data @@ -146,7 +146,7 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { self.buffer.flush() } - /// Writes some vectored data into this BufReader with line buffering. + /// Writes some vectored data into this BufWriter with line buffering. /// /// This means that, if any newlines are present in the data, the data up to /// and including the buffer containing the last newline is sent directly to @@ -256,7 +256,7 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { self.inner().is_write_vectored() } - /// Writes some data into this BufReader with line buffering. + /// Writes some data into this BufWriter with line buffering. /// /// This means that, if any newlines are present in the data, the data up to /// the last newline is sent directly to the underlying writer, and data diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 19b3040dcb279..5da50480c7232 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -184,6 +184,8 @@ pub use alloc_crate::sync::{Arc, Weak}; #[unstable(feature = "mpmc_channel", issue = "126840")] pub mod mpmc; pub mod mpsc; +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub mod oneshot; pub(crate) mod once; // `pub(crate)` for the `sys::sync::once` implementations and `LazyLock`. diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index ee9795a528127..8df81a580f7b8 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -654,7 +654,7 @@ impl Clone for Sender { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Sender { .. }") + f.debug_struct("Sender").finish_non_exhaustive() } } @@ -1380,7 +1380,7 @@ impl Clone for Receiver { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Receiver { .. }") + f.debug_struct("Receiver").finish_non_exhaustive() } } diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index f91c26aa22cf8..0ae23f6e13bf2 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -1114,8 +1114,10 @@ impl error::Error for SendError {} impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - TrySendError::Full(..) => "Full(..)".fmt(f), - TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + TrySendError::Full(..) => f.debug_tuple("TrySendError::Full").finish_non_exhaustive(), + TrySendError::Disconnected(..) => { + f.debug_tuple("TrySendError::Disconnected").finish_non_exhaustive() + } } } } diff --git a/library/std/src/sync/oneshot.rs b/library/std/src/sync/oneshot.rs new file mode 100644 index 0000000000000..ac8ca035165d2 --- /dev/null +++ b/library/std/src/sync/oneshot.rs @@ -0,0 +1,461 @@ +//! A single-producer, single-consumer (oneshot) channel. +//! +//! This is an experimental module, so the API will likely change. + +use crate::sync::mpmc; +use crate::sync::mpsc::{RecvError, SendError}; +use crate::time::{Duration, Instant}; +use crate::{error, fmt}; + +/// Creates a new oneshot channel, returning the sender/receiver halves. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// // Spawn off an expensive computation. +/// thread::spawn(move || { +/// # fn expensive_computation() -> i32 { 42 } +/// sender.send(expensive_computation()).unwrap(); +/// // `sender` is consumed by `send`, so we cannot use it anymore. +/// }); +/// +/// # fn do_other_work() -> i32 { 42 } +/// do_other_work(); +/// +/// // Let's see what that answer was... +/// println!("{:?}", receiver.recv().unwrap()); +/// // `receiver` is consumed by `recv`, so we cannot use it anymore. +/// ``` +#[must_use] +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub fn channel() -> (Sender, Receiver) { + // Using a `sync_channel` with capacity 1 means that the internal implementation will use the + // `Array`-flavored channel implementation. + let (sender, receiver) = mpmc::sync_channel(1); + (Sender { inner: sender }, Receiver { inner: receiver }) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Sender +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The sending half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// sender.send("Hello from thread!").unwrap(); +/// }); +/// +/// assert_eq!(receiver.recv().unwrap(), "Hello from thread!"); +/// ``` +/// +/// `Sender` cannot be sent between threads if it is sending non-`Send` types. +/// +/// ```compile_fail +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::ptr; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// thread::spawn(move || { +/// sender.send(NotSend(ptr::null_mut())); +/// }); +/// +/// let reply = receiver.try_recv().unwrap(); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Sender { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Sender, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Sender`], it is perfectly safe to share a `&Sender` between threads (as it is effectively +// useless without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Sender {} + +impl Sender { + /// Attempts to send a value through this channel. This can only fail if the corresponding + /// [`Receiver`] has been dropped. + /// + /// This method is non-blocking (wait-free). + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// // Perform some computation. + /// let result = 2 + 2; + /// tx.send(result).unwrap(); + /// }); + /// + /// assert_eq!(rx.recv().unwrap(), 4); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn send(self, t: T) -> Result<(), SendError> { + self.inner.send(t) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Sender").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The receiving half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(100)); +/// sender.send("Hello after delay!").unwrap(); +/// }); +/// +/// println!("Waiting for message..."); +/// println!("{}", receiver.recv().unwrap()); +/// ``` +/// +/// `Receiver` cannot be sent between threads if it is receiving non-`Send` types. +/// +/// ```compile_fail +/// # #![feature(oneshot_channel)] +/// # use std::sync::oneshot; +/// # use std::thread; +/// # use std::ptr; +/// # +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// sender.send(NotSend(ptr::null_mut())); +/// +/// thread::spawn(move || { +/// let reply = receiver.try_recv().unwrap(); +/// }); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Receiver { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Receiver, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Receiver`], it is perfectly safe to share a `&Receiver` between threads (as it is unable to +// receive any values without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Receiver {} + +impl Receiver { + /// Receives the value from the sending end, blocking the calling thread until it gets it. + /// + /// Can only fail if the corresponding [`Sender`] has been dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// tx.send("Done!").unwrap(); + /// }); + /// + /// // This will block until the message arrives. + /// println!("{}", rx.recv().unwrap()); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv(self) -> Result { + self.inner.recv() + } + + // Fallible methods. + + /// Attempts to return a pending value on this receiver without blocking. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, mut receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send(42).unwrap(); + /// }); + /// + /// // Keep trying until we get the message, doing other work in the process. + /// loop { + /// match receiver.try_recv() { + /// Ok(value) => { + /// assert_eq!(value, 42); + /// break; + /// } + /// Err(oneshot::TryRecvError::Empty(rx)) => { + /// // Retake ownership of the receiver. + /// receiver = rx; + /// # fn do_other_work() { thread::sleep(Duration::from_millis(25)); } + /// do_other_work(); + /// } + /// Err(oneshot::TryRecvError::Disconnected) => panic!("Sender disconnected"), + /// } + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn try_recv(self) -> Result> { + self.inner.try_recv().map_err(|err| match err { + mpmc::TryRecvError::Empty => TryRecvError::Empty(self), + mpmc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if it waits more than `timeout`. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// sender.send("Success!").unwrap(); + /// }); + /// + /// // Wait up to 1 second for the message + /// match receiver.recv_timeout(Duration::from_secs(1)) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Timed out!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_timeout(self, timeout: Duration) -> Result> { + self.inner.recv_timeout(timeout).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if `deadline` is reached. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send("Just in time!").unwrap(); + /// }); + /// + /// let deadline = Instant::now() + Duration::from_millis(500); + /// match receiver.recv_deadline(deadline) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Missed deadline!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_deadline(self, deadline: Instant) -> Result> { + self.inner.recv_deadline(deadline).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Receiver").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver Errors +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// An error returned from the [`try_recv`](Receiver::try_recv) method. +/// +/// See the documentation for [`try_recv`] for more information on how to use this error. +/// +/// [`try_recv`]: Receiver::try_recv +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum TryRecvError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that [`try_recv`](Receiver::try_recv) + /// took ownership over. + Empty(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +/// An error returned from the [`recv_timeout`](Receiver::recv_timeout) or +/// [`recv_deadline`](Receiver::recv_deadline) methods. +/// +/// # Examples +/// +/// Usage of this error is similar to [`TryRecvError`]. +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot::{self, RecvTimeoutError}; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// // Simulate a long computation that takes longer than our timeout. +/// thread::sleep(Duration::from_millis(500)); +/// sender.send("Too late!".to_string()).unwrap(); +/// }); +/// +/// // Try to receive the message with a short timeout. +/// match receiver.recv_timeout(Duration::from_millis(100)) { +/// Ok(msg) => println!("Received: {}", msg), +/// Err(RecvTimeoutError::Timeout(rx)) => { +/// println!("Timed out waiting for message!"); +/// // You can reuse the receiver if needed. +/// drop(rx); +/// } +/// Err(RecvTimeoutError::Disconnected) => println!("Sender dropped!"), +/// } +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum RecvTimeoutError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that either + /// [`recv_timeout`](Receiver::recv_timeout) or [`recv_deadline`](Receiver::recv_deadline) took + /// ownership over. + Timeout(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("TryRecvError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TryRecvError::Empty(..) => "receiving on an empty oneshot channel".fmt(f), + TryRecvError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for TryRecvError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// + /// This conversion always returns `TryRecvError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("RecvTimeoutError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout(..) => "timed out waiting on oneshot channel".fmt(f), + RecvTimeoutError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for RecvTimeoutError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 7ade9f623147b..32a7efde2a257 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -1,5 +1,6 @@ #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] +#![feature(oneshot_channel)] #![feature(once_cell_try)] #![feature(lock_value_accessors)] #![feature(reentrant_lock)] @@ -26,6 +27,8 @@ mod mutex; mod once; mod once_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod oneshot; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod reentrant_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod rwlock; diff --git a/library/std/tests/sync/oneshot.rs b/library/std/tests/sync/oneshot.rs new file mode 100644 index 0000000000000..6a87c72b9cb5b --- /dev/null +++ b/library/std/tests/sync/oneshot.rs @@ -0,0 +1,342 @@ +//! Inspired by tests from + +use std::sync::mpsc::RecvError; +use std::sync::oneshot; +use std::sync::oneshot::{RecvTimeoutError, TryRecvError}; +use std::time::{Duration, Instant}; +use std::{mem, thread}; + +#[test] +fn send_before_try_recv() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(19i128).is_ok()); + + match receiver.try_recv() { + Ok(19) => {} + _ => panic!("expected Ok(19)"), + } +} + +#[test] +fn send_before_recv() { + let (sender, receiver) = oneshot::channel::<()>(); + + assert!(sender.send(()).is_ok()); + assert_eq!(receiver.recv(), Ok(())); + + let (sender, receiver) = oneshot::channel::(); + + assert!(sender.send(42).is_ok()); + assert_eq!(receiver.recv(), Ok(42)); + + let (sender, receiver) = oneshot::channel::<[u8; 4096]>(); + + assert!(sender.send([0b10101010; 4096]).is_ok()); + assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]); +} + +#[test] +fn sender_drop() { + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + } + } + + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.try_recv() { + Err(TryRecvError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } +} + +#[test] +fn send_never_deadline() { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_deadline(Instant::now()) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } +} + +#[test] +fn send_before_recv_timeout() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(22i128).is_ok()); + + let start = Instant::now(); + + let timeout = Duration::from_secs(1); + match receiver.recv_timeout(timeout) { + Ok(22) => {} + _ => panic!("expected Ok(22)"), + } + + assert!(start.elapsed() < timeout); +} + +#[test] +fn send_error() { + let (sender, receiver) = oneshot::channel(); + + mem::drop(receiver); + + let send_error = sender.send(32u128).unwrap_err(); + assert_eq!(send_error.0, 32); +} + +#[test] +fn recv_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + sender.send(9u128).unwrap(); + }); + let t2 = thread::spawn(move || { + assert_eq!(receiver.recv(), Ok(9)); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn recv_timeout_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + sender.send(99u128).unwrap(); + }); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Ok(99) => {} + _ => panic!("expected Ok(99)"), + } + + t.join().unwrap(); +} + +#[test] +fn recv_then_drop_sender() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + }); + + let t2 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn drop_sender_then_recv() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + let t2 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected disconnected error"), + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn try_recv_empty() { + let (sender, receiver) = oneshot::channel::(); + match receiver.try_recv() { + Err(TryRecvError::Empty(_)) => {} + _ => panic!("expected empty error"), + } + mem::drop(sender); +} + +#[test] +fn try_recv_then_drop_receiver() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + let _ = sender.send(42); + }); + + let t2 = thread::spawn(move || match receiver.try_recv() { + Ok(_) => {} + Err(TryRecvError::Empty(r)) => { + mem::drop(r); + } + Err(TryRecvError::Disconnected) => {} + }); + + t2.join().unwrap(); + t1.join().unwrap(); +} + +#[test] +fn recv_no_time() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + match receiver.recv_deadline(start) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + let (_sender, receiver) = oneshot::channel::(); + match receiver.recv_timeout(Duration::from_millis(0)) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } +} + +#[test] +fn recv_deadline_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + + match receiver.recv_deadline(start + timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn recv_time_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + match receiver.recv_timeout(timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn non_send_type_can_be_used_on_same_thread() { + use std::ptr; + + #[derive(Debug, Eq, PartialEq)] + struct NotSend(*mut ()); + + let (sender, receiver) = oneshot::channel(); + sender.send(NotSend(ptr::null_mut())).unwrap(); + let reply = receiver.try_recv().unwrap(); + assert_eq!(reply, NotSend(ptr::null_mut())); +} + +/// Helper for testing drop behavior (taken directly from the `oneshot` crate). +struct DropCounter { + count: std::rc::Rc>, +} + +impl DropCounter { + fn new() -> (DropTracker, DropCounter) { + let count = std::rc::Rc::new(std::cell::RefCell::new(0)); + (DropTracker { count: count.clone() }, DropCounter { count }) + } + + fn count(&self) -> usize { + *self.count.borrow() + } +} + +struct DropTracker { + count: std::rc::Rc>, +} + +impl Drop for DropTracker { + fn drop(&mut self) { + *self.count.borrow_mut() += 1; + } +} + +#[test] +fn message_in_channel_dropped_on_receiver_drop() { + let (sender, receiver) = oneshot::channel(); + + let (message, counter) = DropCounter::new(); + assert_eq!(counter.count(), 0); + + sender.send(message).unwrap(); + assert_eq!(counter.count(), 0); + + mem::drop(receiver); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + mem::drop(send_error); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly_on_extract() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + let message = send_error.0; // Access the inner value directly + assert_eq!(counter.count(), 0); + + mem::drop(message); + assert_eq!(counter.count(), 1); +} diff --git a/library/stdarch/crates/core_arch/src/riscv64/zk.rs b/library/stdarch/crates/core_arch/src/riscv64/zk.rs index a30653cbe0885..3aa1ca39b3c94 100644 --- a/library/stdarch/crates/core_arch/src/riscv64/zk.rs +++ b/library/stdarch/crates/core_arch/src/riscv64/zk.rs @@ -1,6 +1,8 @@ #[cfg(test)] use stdarch_test::assert_instr; +use crate::arch::asm; + unsafe extern "unadjusted" { #[link_name = "llvm.riscv.aes64es"] fn _aes64es(rs1: i64, rs2: i64) -> i64; @@ -14,12 +16,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.riscv.aes64dsm"] fn _aes64dsm(rs1: i64, rs2: i64) -> i64; - #[link_name = "llvm.riscv.aes64ks1i"] - fn _aes64ks1i(rs1: i64, rnum: i32) -> i64; - - #[link_name = "llvm.riscv.aes64ks2"] - fn _aes64ks2(rs1: i64, rs2: i64) -> i64; - #[link_name = "llvm.riscv.aes64im"] fn _aes64im(rs1: i64) -> i64; @@ -133,15 +129,26 @@ pub fn aes64dsm(rs1: u64, rs2: u64) -> u64 { /// # Note /// /// The `RNUM` parameter is expected to be a constant value inside the range of `0..=10`. -#[target_feature(enable = "zkne", enable = "zknd")] +#[target_feature(enable = "zkne_or_zknd")] #[rustc_legacy_const_generics(1)] -#[cfg_attr(test, assert_instr(aes64ks1i, RNUM = 0))] #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub fn aes64ks1i(rs1: u64) -> u64 { static_assert!(RNUM <= 10); - - unsafe { _aes64ks1i(rs1 as i64, RNUM as i32) as u64 } + unsafe { + let rd: u64; + asm!( + ".option push", + ".option arch, +zkne", + "aes64ks1i {}, {}, {}", + ".option pop", + lateout(reg) rd, + in(reg) rs1, + const RNUM, + options(pure, nomem, nostack, preserves_flags) + ); + rd + } } /// This instruction implements part of the KeySchedule operation for the AES Block cipher. @@ -155,12 +162,24 @@ pub fn aes64ks1i(rs1: u64) -> u64 { /// Version: v1.0.1 /// /// Section: 3.11 -#[target_feature(enable = "zkne", enable = "zknd")] -#[cfg_attr(test, assert_instr(aes64ks2))] +#[target_feature(enable = "zkne_or_zknd")] #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub fn aes64ks2(rs1: u64, rs2: u64) -> u64 { - unsafe { _aes64ks2(rs1 as i64, rs2 as i64) as u64 } + unsafe { + let rd: u64; + asm!( + ".option push", + ".option arch, +zkne", + "aes64ks2 {}, {}, {}", + ".option pop", + lateout(reg) rd, + in(reg) rs1, + in(reg) rs2, + options(pure, nomem, nostack, preserves_flags) + ); + rd + } } /// This instruction accelerates the inverse MixColumns step of the AES Block Cipher, and is used to aid creation of diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index 4c3d456b9af80..23c2dc688400b 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -7,7 +7,7 @@ The tracking issue for this feature is: [#87121] ------------------------ > **Note**: This feature is incomplete. In the future, it is meant to supersede -> [`box_patterns`] and [`string_deref_patterns`]. +> [`box_patterns`]. This feature permits pattern matching on [smart pointers in the standard library] through their `Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which @@ -103,5 +103,4 @@ match *(b"test" as &[u8]) { ``` [`box_patterns`]: ./box-patterns.md -[`string_deref_patterns`]: ./string-deref-patterns.md [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors diff --git a/src/doc/unstable-book/src/language-features/string-deref-patterns.md b/src/doc/unstable-book/src/language-features/string-deref-patterns.md deleted file mode 100644 index 366bb15d4ea86..0000000000000 --- a/src/doc/unstable-book/src/language-features/string-deref-patterns.md +++ /dev/null @@ -1,48 +0,0 @@ -# `string_deref_patterns` - -The tracking issue for this feature is: [#87121] - -[#87121]: https://github.com/rust-lang/rust/issues/87121 - ------------------------- - -> **Note**: This feature will be superseded by [`deref_patterns`] in the future. - -This feature permits pattern matching `String` to `&str` through [its `Deref` implementation]. - -```rust -#![feature(string_deref_patterns)] - -pub enum Value { - String(String), - Number(u32), -} - -pub fn is_it_the_answer(value: Value) -> bool { - match value { - Value::String("42") => true, - Value::Number(42) => true, - _ => false, - } -} -``` - -Without this feature other constructs such as match guards have to be used. - -```rust -# pub enum Value { -# String(String), -# Number(u32), -# } -# -pub fn is_it_the_answer(value: Value) -> bool { - match value { - Value::String(s) if s == "42" => true, - Value::Number(42) => true, - _ => false, - } -} -``` - -[`deref_patterns`]: ./deref-patterns.md -[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String diff --git a/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir index 9f52a8cd1e55e..c7c26d6351ad2 100644 --- a/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir +++ b/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir @@ -7,10 +7,11 @@ fn foo(_1: Option) -> i32 { let mut _3: isize; let mut _4: &std::string::String; let mut _5: &str; - let mut _6: bool; - let _7: std::option::Option; + let mut _6: &str; + let mut _7: bool; + let _8: std::option::Option; scope 1 { - debug s => _7; + debug s => _8; } bb0: { @@ -26,11 +27,12 @@ fn foo(_1: Option) -> i32 { } bb2: { - _6 = ::eq(copy _5, const "a") -> [return: bb3, unwind unreachable]; + _6 = &(*_5); + _7 = ::eq(copy _6, const "a") -> [return: bb3, unwind unreachable]; } bb3: { - switchInt(move _6) -> [0: bb5, otherwise: bb4]; + switchInt(move _7) -> [0: bb5, otherwise: bb4]; } bb4: { @@ -39,15 +41,15 @@ fn foo(_1: Option) -> i32 { } bb5: { - StorageLive(_7); + StorageLive(_8); _2 = const false; - _7 = move _1; + _8 = move _1; _0 = const 4321_i32; - drop(_7) -> [return: bb6, unwind unreachable]; + drop(_8) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_7); + StorageDead(_8); goto -> bb7; } diff --git a/tests/mir-opt/building/match/deref-patterns/string.rs b/tests/mir-opt/building/match/deref-patterns/string.rs index bb4b5379b2751..1f8d6fbb0bd25 100644 --- a/tests/mir-opt/building/match/deref-patterns/string.rs +++ b/tests/mir-opt/building/match/deref-patterns/string.rs @@ -1,7 +1,8 @@ // skip-filecheck //@ compile-flags: -Z mir-opt-level=0 -C panic=abort -#![feature(string_deref_patterns)] +#![feature(deref_patterns)] +#![expect(incomplete_features)] #![crate_type = "lib"] // EMIT_MIR string.foo.PreCodegen.after.mir diff --git a/tests/ui/README.md b/tests/ui/README.md index b1c813cce93fb..4c91f313a7351 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -380,12 +380,6 @@ These tests use the unstable command line option `query-dep-graph` to examine th Tests for `#[deprecated]` attribute and `deprecated_in_future` internal lint. -## `tests/ui/deref-patterns/`: `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]` - -Tests for `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`. See [Deref patterns | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/deref-patterns.html). - -**FIXME**: May have some overlap with `tests/ui/pattern/deref-patterns`. - ## `tests/ui/derived-errors/`: Derived Error Messages Tests for quality of diagnostics involving suppression of cascading errors in some cases to avoid overwhelming the user. diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 72edc03e10a42..6125e66320c8a 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -424,6 +424,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zkn` `zknd` `zkne` +`zkne_or_zknd` `zknh` `zkr` `zks` diff --git a/tests/ui/deref-patterns/gate.rs b/tests/ui/deref-patterns/gate.rs deleted file mode 100644 index 835fdf854d2c4..0000000000000 --- a/tests/ui/deref-patterns/gate.rs +++ /dev/null @@ -1,7 +0,0 @@ -// gate-test-string_deref_patterns -fn main() { - match String::new() { - "" | _ => {} - //~^ ERROR mismatched types - } -} diff --git a/tests/ui/deref-patterns/gate.stderr b/tests/ui/deref-patterns/gate.stderr deleted file mode 100644 index e3cbded339d7f..0000000000000 --- a/tests/ui/deref-patterns/gate.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/gate.rs:4:9 - | -LL | match String::new() { - | ------------- this expression has type `String` -LL | "" | _ => {} - | ^^ expected `String`, found `&str` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/deref-patterns/basic.rs b/tests/ui/pattern/deref-patterns/basic.rs similarity index 83% rename from tests/ui/deref-patterns/basic.rs rename to tests/ui/pattern/deref-patterns/basic.rs index d76fb697f4062..dee4521e1f95c 100644 --- a/tests/ui/deref-patterns/basic.rs +++ b/tests/ui/pattern/deref-patterns/basic.rs @@ -1,6 +1,7 @@ //@ run-pass //@ check-run-results -#![feature(string_deref_patterns)] +#![feature(deref_patterns)] +#![expect(incomplete_features)] fn main() { test(Some(String::from("42"))); diff --git a/tests/ui/deref-patterns/basic.run.stdout b/tests/ui/pattern/deref-patterns/basic.run.stdout similarity index 100% rename from tests/ui/deref-patterns/basic.run.stdout rename to tests/ui/pattern/deref-patterns/basic.run.stdout diff --git a/tests/ui/deref-patterns/default-infer.rs b/tests/ui/pattern/deref-patterns/default-infer.rs similarity index 66% rename from tests/ui/deref-patterns/default-infer.rs rename to tests/ui/pattern/deref-patterns/default-infer.rs index 4f926175bd335..fb0b2add132a3 100644 --- a/tests/ui/deref-patterns/default-infer.rs +++ b/tests/ui/pattern/deref-patterns/default-infer.rs @@ -1,5 +1,6 @@ //@ check-pass -#![feature(string_deref_patterns)] +#![feature(deref_patterns)] +#![expect(incomplete_features)] fn main() { match <_ as Default>::default() { diff --git a/tests/ui/deref-patterns/refs.rs b/tests/ui/pattern/deref-patterns/refs.rs similarity index 79% rename from tests/ui/deref-patterns/refs.rs rename to tests/ui/pattern/deref-patterns/refs.rs index c93e579bfd804..51826225856bd 100644 --- a/tests/ui/deref-patterns/refs.rs +++ b/tests/ui/pattern/deref-patterns/refs.rs @@ -1,5 +1,6 @@ //@ check-pass -#![feature(string_deref_patterns)] +#![feature(deref_patterns)] +#![expect(incomplete_features)] fn foo(s: &String) -> i32 { match *s {