diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index ccbe7325cc6c2..955e739b2c126 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -552,7 +552,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation( - utils::debug_context(self).llcontext, line.unwrap_or(UNKNOWN_LINE_NUMBER), col.unwrap_or(UNKNOWN_COLUMN_NUMBER), scope, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e359d9f8c9c77..eb4f36266dbae 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2102,7 +2102,6 @@ extern "C" { ); pub fn LLVMRustDIBuilderCreateDebugLocation( - Context: &'a Context, Line: c_uint, Column: c_uint, Scope: &'a DIScope, diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 509f81e16536b..f8ceb94916e7c 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -798,7 +798,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(util::commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(util::release_str())); - if cfg!(llvm) { + if cfg!(feature = "llvm") { get_builtin_codegen_backend("llvm")().print_version(); } } @@ -1087,7 +1087,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.iter().any(|x| *x == "passes=list") { - if cfg!(llvm) { + if cfg!(feature = "llvm") { get_builtin_codegen_backend("llvm")().print_passes(); } return None; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c0ff62c17beb5..1d6f00562f136 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -994,11 +994,9 @@ LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line, - unsigned Column, LLVMMetadataRef Scope, +LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, + LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) { - LLVMContext &Context = *unwrap(ContextRef); - DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr(Scope), unwrapDIPtr(InlinedAt)); diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index b775846bba452..65e5301c96e9e 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -29,9 +29,10 @@ //! contained no `DefId` for thing that had been removed. //! //! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `dep_constructor` module. The -//! `dep_constructor` module links a `DepKind` to the parameters that are needed at -//! runtime in order to construct a valid `DepNode` fingerprint. +//! defines the `DepKind` enum. Each `DepKind` has its own parameters that are +//! needed at runtime in order to construct a valid `DepNode` fingerprint. +//! However, only `CompileCodegenUnit` is constructed explicitly (with +//! `make_compile_codegen_unit`). //! //! Because the macro sees what parameters a given `DepKind` requires, it can //! "infer" some properties for each kind of `DepNode`: @@ -44,22 +45,14 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. //! -//! The `dep_constructor` module, together with `DepNode::new()`, ensures that only +//! `make_compile_codegen_unit`, together with `DepNode::new()`, ensures that only //! valid `DepNode` instances can be constructed. For example, the API does not //! allow for constructing parameterless `DepNode`s with anything other //! than a zeroed out fingerprint. More generally speaking, it relieves the //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::subst::{GenericArg, SubstsRef}; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::TyCtxt; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; @@ -338,25 +331,6 @@ macro_rules! define_dep_nodes { $($variant),* } - #[allow(non_camel_case_types)] - pub mod dep_constructor { - use super::*; - - $( - #[inline(always)] - #[allow(unreachable_code, non_snake_case)] - pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { - // tuple args - $({ - erase!($tuple_arg_ty); - return DepNode::construct(_tcx, DepKind::$variant, &arg) - })* - - return DepNode::construct(_tcx, DepKind::$variant, &()) - } - )* - } - fn dep_kind_from_label_string(label: &str) -> Result { match label { $(stringify!($variant) => Ok(DepKind::$variant),)* @@ -384,9 +358,16 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [anon] TraitSelect, + // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. [] CompileCodegenUnit(Symbol), ]); +// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. +// Be very careful changing this type signature! +crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { + DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) +} + pub type DepNode = rustc_query_system::dep_graph::DepNode; // We keep a lot of `DepNode`s in memory during compilation. It's not diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 22e9cc1cd3ee4..ea4d8c1299709 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -13,7 +13,8 @@ pub use rustc_query_system::dep_graph::{ WorkProduct, WorkProductId, }; -pub use dep_node::{dep_constructor, label_strs, DepKind, DepNode, DepNodeExt}; +crate use dep_node::make_compile_codegen_unit; +pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index f810f6a56a520..6d5d408f86c15 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId}; +use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; @@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { - dep_constructor::CompileCodegenUnit(tcx, self.name()) + crate::dep_graph::make_compile_codegen_unit(tcx, self.name()) } } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index a8f2b4d60e140..75f80f69beafc 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -823,7 +823,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> } if !tcx.is_mir_available(def_id) { - bug!("cannot create local mono-item for {:?}", def_id) + bug!("no MIR available for {:?}", def_id); } true diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5fc573a57ad0b..ecc6e8599ad01 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -15,6 +15,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; +use rustc_span::{BytePos, DUMMY_SP}; use rustc_trait_selection::traits::{ObligationCause, Pattern}; use std::cmp; @@ -1001,7 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // More generally, the expected type wants a tuple variant with one field of an // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. - let missing_parenthesis = match (&expected.kind(), fields, had_err) { + let missing_parentheses = match (&expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the substs could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. @@ -1014,13 +1015,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => false, }; - if missing_parenthesis { + if missing_parentheses { let (left, right) = match subpats { // This is the zero case; we aim to get the "hi" part of the `QPath`'s // span as the "lo" and then the "hi" part of the pattern's span as the "hi". // This looks like: // - // help: missing parenthesis + // help: missing parentheses // | // L | let A(()) = A(()); // | ^ ^ @@ -1029,17 +1030,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // last sub-pattern. In the case of `A(x)` the first and last may coincide. // This looks like: // - // help: missing parenthesis + // help: missing parentheses // | // L | let A((x, y)) = A((1, 2)); // | ^ ^ [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span), }; err.multipart_suggestion( - "missing parenthesis", + "missing parentheses", vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())], Applicability::MachineApplicable, ); + } else if fields.len() > subpats.len() { + let after_fields_span = if pat_span == DUMMY_SP { + pat_span + } else { + pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi() + }; + let all_fields_span = match subpats { + [] => after_fields_span, + [field] => field.span, + [first, .., last] => first.span.to(last.span), + }; + + // Check if all the fields in the pattern are wildcards. + let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild)); + + let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", "); + if !subpats.is_empty() { + wildcard_sugg = String::from(", ") + &wildcard_sugg; + } + + err.span_suggestion_verbose( + after_fields_span, + "use `_` to explicitly ignore each field", + wildcard_sugg, + Applicability::MaybeIncorrect, + ); + + // Only suggest `..` if more than one field is missing + // or the pattern consists of all wildcards. + if fields.len() - subpats.len() > 1 || all_wildcards { + if subpats.is_empty() || all_wildcards { + err.span_suggestion_verbose( + all_fields_span, + "use `..` to ignore all fields", + String::from(".."), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + after_fields_span, + "use `..` to ignore the rest of the fields", + String::from(", .."), + Applicability::MaybeIncorrect, + ); + } + } } err.emit(); diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index e8e1e66da5ed4..5067af1d4ff68 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -370,7 +370,7 @@ fn test_weak_count_locked() { let n = Arc::weak_count(&a2); assert!(n < 2, "bad weak count: {}", n); #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint. - atomic::spin_loop_hint(); + std::hint::spin_loop(); } t.join().unwrap(); } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1ca194c336112..ccc4f03a1e505 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1953,27 +1953,6 @@ impl Vec { } } -impl Vec { - /// Removes the first instance of `item` from the vector if the item exists. - /// - /// This method will be removed soon. - #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")] - #[rustc_deprecated( - reason = "Removing the first item equal to a needle is already easily possible \ - with iterators and the current Vec methods. Furthermore, having a method for \ - one particular case of removal (linear search, only the first item, no swap remove) \ - but not for others is inconsistent. This method will be removed soon.", - since = "1.46.0" - )] - pub fn remove_item(&mut self, item: &V) -> Option - where - T: PartialEq, - { - let pos = self.iter().position(|x| *x == *item)?; - Some(self.remove(pos)) - } -} - //////////////////////////////////////////////////////////////////////////////// // Internal methods and functions //////////////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0c65c1c9eb7e9..73cf5d138bf75 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -456,7 +456,9 @@ impl Display for Arguments<'_> { /// /// When used with the alternate format specifier `#?`, the output is pretty-printed. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// This trait can be used with `#[derive]` if all fields implement `Debug`. When /// `derive`d for structs, it will use the name of the `struct`, then `{`, then a @@ -602,7 +604,9 @@ pub use macros::Debug; /// `Display` is similar to [`Debug`], but `Display` is for user-facing /// output, and so cannot be derived. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -674,7 +678,9 @@ pub trait Display { /// /// The alternate flag, `#`, adds a `0o` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -726,7 +732,9 @@ pub trait Octal { /// /// The alternate flag, `#`, adds a `0b` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -782,7 +790,9 @@ pub trait Binary { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -835,7 +845,9 @@ pub trait LowerHex { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -883,7 +895,9 @@ pub trait UpperHex { /// The `Pointer` trait should format its output as a memory location. This is commonly presented /// as hexadecimal. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -932,7 +946,9 @@ pub trait Pointer { /// /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -981,7 +997,9 @@ pub trait LowerExp { /// /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -1555,7 +1573,7 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// // We set alignment to the left with ">". + /// // We set alignment to the right with ">". /// assert_eq!(&format!("{:G>3}", Foo), "GGG"); /// assert_eq!(&format!("{:t>6}", Foo), "tttttt"); /// ``` diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 362326725490f..1d01e9b5fb7dc 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,6 +1,9 @@ use super::Peekable; /// An iterator adapter that places a separator between all elements. +/// +/// This `struct` is created by [`Iterator::intersperse`]. See its documentation +/// for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse @@ -40,37 +43,146 @@ where } } - fn fold(mut self, init: B, mut f: F) -> B + fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; + let separator = self.separator; + intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep) + } + + fn size_hint(&self) -> (usize, Option) { + intersperse_size_hint(&self.iter, self.needs_sep) + } +} + +/// An iterator adapter that places a separator between all elements. +/// +/// This `struct` is created by [`Iterator::intersperse_with`]. See its +/// documentation for more information. +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +pub struct IntersperseWith +where + I: Iterator, +{ + separator: G, + iter: Peekable, + needs_sep: bool, +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl crate::fmt::Debug for IntersperseWith +where + I: Iterator + crate::fmt::Debug, + I::Item: crate::fmt::Debug, + G: crate::fmt::Debug, +{ + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + f.debug_struct("IntersperseWith") + .field("separator", &self.separator) + .field("iter", &self.iter) + .field("needs_sep", &self.needs_sep) + .finish() + } +} - // Use `peek()` first to avoid calling `next()` on an empty iterator. - if !self.needs_sep || self.iter.peek().is_some() { - if let Some(x) = self.iter.next() { - accum = f(accum, x); - } +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl crate::clone::Clone for IntersperseWith +where + I: Iterator + crate::clone::Clone, + I::Item: crate::clone::Clone, + G: Clone, +{ + fn clone(&self) -> Self { + IntersperseWith { + separator: self.separator.clone(), + iter: self.iter.clone(), + needs_sep: self.needs_sep.clone(), } + } +} - let element = &self.separator; +impl IntersperseWith +where + I: Iterator, + G: FnMut() -> I::Item, +{ + pub(in crate::iter) fn new(iter: I, separator: G) -> Self { + Self { iter: iter.peekable(), separator, needs_sep: false } + } +} - self.iter.fold(accum, |mut accum, x| { - accum = f(accum, element.clone()); - accum = f(accum, x); - accum - }) +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl Iterator for IntersperseWith +where + I: Iterator, + G: FnMut() -> I::Item, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.needs_sep && self.iter.peek().is_some() { + self.needs_sep = false; + Some((self.separator)()) + } else { + self.needs_sep = true; + self.iter.next() + } + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + intersperse_fold(self.iter, init, f, self.separator, self.needs_sep) } fn size_hint(&self) -> (usize, Option) { - let (lo, hi) = self.iter.size_hint(); - let next_is_elem = !self.needs_sep; - let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); - let hi = match hi { - Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), - None => None, - }; - (lo, hi) + intersperse_size_hint(&self.iter, self.needs_sep) } } + +fn intersperse_size_hint(iter: &I, needs_sep: bool) -> (usize, Option) +where + I: Iterator, +{ + let (lo, hi) = iter.size_hint(); + let next_is_elem = !needs_sep; + let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); + let hi = match hi { + Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), + None => None, + }; + (lo, hi) +} + +fn intersperse_fold( + mut iter: Peekable, + init: B, + mut f: F, + mut separator: G, + needs_sep: bool, +) -> B +where + I: Iterator, + F: FnMut(B, I::Item) -> B, + G: FnMut() -> I::Item, +{ + let mut accum = init; + + // Use `peek()` first to avoid calling `next()` on an empty iterator. + if !needs_sep || iter.peek().is_some() { + if let Some(x) = iter.next() { + accum = f(accum, x); + } + } + + iter.fold(accum, |mut accum, x| { + accum = f(accum, separator()); + accum = f(accum, x); + accum + }) +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 7dfbf32cea7b8..41a7b13232adf 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -43,7 +43,7 @@ pub use self::flatten::Flatten; pub use self::copied::Copied; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -pub use self::intersperse::Intersperse; +pub use self::intersperse::{Intersperse, IntersperseWith}; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::map_while::MapWhile; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 569de719d03d6..c57ba2bf62645 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -395,8 +395,6 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -pub use self::adapters::Intersperse; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; #[unstable(feature = "inplace_iteration", issue = "none")] @@ -410,6 +408,8 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 0023de65d2b3b..83d339d8f40a5 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -8,7 +8,7 @@ use crate::ops::{Add, ControlFlow, Try}; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; -use super::super::{FromIterator, Intersperse, Product, Sum, Zip}; +use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, }; @@ -571,6 +571,9 @@ pub trait Iterator { /// Places a copy of `separator` between all elements. /// + /// In case the separator does not implement [`Clone`] or needs to be + /// computed every time, use [`intersperse_with`]. + /// /// # Examples /// /// Basic usage: @@ -578,9 +581,12 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::(); - /// assert_eq!(hello, "Hello World"); + /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::(); + /// assert_eq!(hello, "Hello World !"); /// ``` + /// + /// [`Clone`]: crate::clone::Clone + /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse(self, separator: Self::Item) -> Intersperse @@ -591,6 +597,33 @@ pub trait Iterator { Intersperse::new(self, separator) } + /// Places an element generated by `separator` between all elements. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_intersperse)] + /// + /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); + /// + /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied(); + /// let separator = || happy_emojis.next().unwrap_or(" 🦀 "); + /// + /// let result = src.intersperse_with(separator).collect::(); + /// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!"); + /// ``` + #[inline] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + fn intersperse_with(self, separator: G) -> IntersperseWith + where + Self: Sized, + G: FnMut() -> Self::Item, + { + IntersperseWith::new(self, separator) + } + /// Takes a closure and creates an iterator which calls that closure on each /// element. /// diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 1634aff7b4dc9..90964bae98c89 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -401,7 +401,7 @@ macro_rules! write { /// For more information, see [`write!`]. For information on the format string syntax, see /// [`std::fmt`]. /// -/// [`std::fmt`]: crate::fmt +/// [`std::fmt`]: ../std/fmt/index.html /// /// # Examples /// @@ -730,7 +730,7 @@ pub(crate) mod builtin { /// [`Display`]: crate::fmt::Display /// [`Debug`]: crate::fmt::Debug /// [`fmt::Arguments`]: crate::fmt::Arguments - /// [`std::fmt`]: crate::fmt + /// [`std::fmt`]: ../std/fmt/index.html /// [`format!`]: ../std/macro.format.html /// [`println!`]: ../std/macro.println.html /// @@ -1194,7 +1194,7 @@ pub(crate) mod builtin { /// be provided with or without arguments for formatting. See [`std::fmt`] /// for syntax for this form. /// - /// [`std::fmt`]: crate::fmt + /// [`std::fmt`]: ../std/fmt/index.html /// /// # Examples /// diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 1d67e65e51f5f..0571dc74b9af9 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -678,6 +678,29 @@ pub enum Bound { Unbounded, } +#[unstable(feature = "bound_as_ref", issue = "80996")] +impl Bound { + /// Converts from `&Bound` to `Bound<&T>`. + #[inline] + pub fn as_ref(&self) -> Bound<&T> { + match *self { + Included(ref x) => Included(x), + Excluded(ref x) => Excluded(x), + Unbounded => Unbounded, + } + } + + /// Converts from `&mut Bound` to `Bound<&T>`. + #[inline] + pub fn as_mut(&mut self) -> Bound<&mut T> { + match *self { + Included(ref mut x) => Included(x), + Excluded(ref mut x) => Excluded(x), + Unbounded => Unbounded, + } + } +} + impl Bound<&T> { /// Map a `Bound<&T>` to a `Bound` by cloning the contents of the bound. /// diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 081d80f487605..6de2714059480 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1877,7 +1877,7 @@ impl [T] { /// Some(b"llo".as_ref())); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[stable(feature = "slice_strip", since = "1.50.0")] + #[stable(feature = "slice_strip", since = "1.51.0")] pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> where T: PartialEq, @@ -1911,7 +1911,7 @@ impl [T] { /// assert_eq!(v.strip_suffix(&[50, 30]), None); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[stable(feature = "slice_strip", since = "1.50.0")] + #[stable(feature = "slice_strip", since = "1.51.0")] pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> where T: PartialEq, @@ -3323,7 +3323,7 @@ pub trait SlicePattern { fn as_slice(&self) -> &[Self::Item]; } -#[stable(feature = "slice_strip", since = "1.50.0")] +#[stable(feature = "slice_strip", since = "1.51.0")] impl SlicePattern for [T] { type Item = T; @@ -3333,7 +3333,7 @@ impl SlicePattern for [T] { } } -#[stable(feature = "slice_strip", since = "1.50.0")] +#[stable(feature = "slice_strip", since = "1.51.0")] impl SlicePattern for [T; N] { type Item = T; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index a167f0ffa09ec..81c9e1d1c10b2 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -120,21 +120,6 @@ use crate::intrinsics; use crate::hint::spin_loop; -/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). -/// -/// This function is expected to be deprecated in favor of -/// [`hint::spin_loop`]. -/// -/// **Note**: On platforms that do not support receiving spin-loop hints this function does not -/// do anything at all. -/// -/// [`hint::spin_loop`]: crate::hint::spin_loop -#[inline] -#[stable(feature = "spin_loop_hint", since = "1.24.0")] -pub fn spin_loop_hint() { - spin_loop() -} - /// A boolean type which can be safely shared between threads. /// /// This type has the same in-memory representation as a [`bool`]. @@ -2791,3 +2776,15 @@ impl fmt::Pointer for AtomicPtr { fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f) } } + +/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). +/// +/// This function is deprecated in favor of [`hint::spin_loop`]. +/// +/// [`hint::spin_loop`]: crate::hint::spin_loop +#[inline] +#[stable(feature = "spin_loop_hint", since = "1.24.0")] +#[rustc_deprecated(since = "1.51.0", reason = "use hint::spin_loop instead")] +pub fn spin_loop_hint() { + spin_loop() +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 7376e7848eff5..691767edea6d9 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3508,6 +3508,12 @@ pub fn extend_for_unit() { #[test] fn test_intersperse() { + let v = std::iter::empty().intersperse(0u32).collect::>(); + assert_eq!(v, vec![]); + + let v = std::iter::once(1).intersperse(0).collect::>(); + assert_eq!(v, vec![1]); + let xs = ["a", "", "b", "c"]; let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); let text: String = v.concat(); @@ -3520,6 +3526,9 @@ fn test_intersperse() { #[test] fn test_intersperse_size_hint() { + let iter = std::iter::empty::().intersperse(0); + assert_eq!(iter.size_hint(), (0, Some(0))); + let xs = ["a", "", "b", "c"]; let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); assert_eq!(iter.size_hint(), (7, Some(7))); @@ -3587,3 +3596,24 @@ fn test_try_fold_specialization_intersperse_err() { iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); assert_eq!(iter.next(), None); } + +#[test] +fn test_intersperse_with() { + #[derive(PartialEq, Debug)] + struct NotClone { + u: u32, + } + let r = vec![NotClone { u: 0 }, NotClone { u: 1 }] + .into_iter() + .intersperse_with(|| NotClone { u: 2 }) + .collect::>(); + assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); + + let mut ctr = 100; + let separator = || { + ctr *= 2; + ctr + }; + let r = (0..3).intersperse_with(separator).collect::>(); + assert_eq!(r, vec![0, 200, 1, 400, 2]); +} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 7ad9e446c5997..3f5b7c0b29be6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -366,7 +366,6 @@ where { let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf }; - let ret; loop { if g.len == g.buf.len() { unsafe { @@ -385,21 +384,20 @@ where } } - match r.read(&mut g.buf[g.len..]) { - Ok(0) => { - ret = Ok(g.len - start_len); - break; + let buf = &mut g.buf[g.len..]; + match r.read(buf) { + Ok(0) => return Ok(g.len - start_len), + Ok(n) => { + // We can't allow bogus values from read. If it is too large, the returned vec could have its length + // set past its capacity, or if it overflows the vec could be shortened which could create an invalid + // string if this is called via read_to_string. + assert!(n <= buf.len()); + g.len += n; } - Ok(n) => g.len += n, Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - - ret } pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result @@ -944,6 +942,54 @@ pub trait Read { } } +/// Read all bytes from a [reader][Read] into a new [`String`]. +/// +/// This is a convenience function for [`Read::read_to_string`]. Using this +/// function avoids having to create a variable first and provides more type +/// safety since you can only get the buffer out if there were no errors. (If you +/// use [`Read::read_to_string`] you have to remember to check whether the read +/// succeeded because otherwise your buffer will be empty or only partially full.) +/// +/// # Performance +/// +/// The downside of this function's increased ease of use and type safety is +/// that it gives you less control over performance. For example, you can't +/// pre-allocate memory like you can using [`String::with_capacity`] and +/// [`Read::read_to_string`]. Also, you can't re-use the buffer if an error +/// occurs while reading. +/// +/// In many cases, this function's performance will be adequate and the ease of use +/// and type safety tradeoffs will be worth it. However, there are cases where you +/// need more control over performance, and in those cases you should definitely use +/// [`Read::read_to_string`] directly. +/// +/// # Errors +/// +/// This function forces you to handle errors because the output (the `String`) +/// is wrapped in a [`Result`]. See [`Read::read_to_string`] for the errors +/// that can occur. If any error occurs, you will get an [`Err`], so you +/// don't have to worry about your buffer being empty or partially full. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(io_read_to_string)] +/// +/// # use std::io; +/// fn main() -> io::Result<()> { +/// let stdin = io::read_to_string(&mut io::stdin())?; +/// println!("Stdin was:"); +/// println!("{}", stdin); +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "io_read_to_string", issue = "80218")] +pub fn read_to_string(reader: &mut R) -> Result { + let mut buf = String::new(); + reader.read_to_string(&mut buf)?; + Ok(buf) +} + /// A buffer type used with `Read::read_vectored`. /// /// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index f988a019cfedb..885389ca54cd4 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -1,9 +1,10 @@ use crate::cell::UnsafeCell; use crate::collections::VecDeque; use crate::ffi::c_void; +use crate::hint; use crate::ops::{Deref, DerefMut, Drop}; use crate::ptr; -use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::hermit::abi; /// This type provides a lock based on busy waiting to realize mutual exclusion @@ -46,7 +47,7 @@ impl Spinlock { fn obtain_lock(&self) { let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1; while self.dequeue.load(Ordering::SeqCst) != ticket { - spin_loop_hint(); + hint::spin_loop(); } } diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs index 9140041c58414..7f1a671bab4eb 100644 --- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -2,8 +2,9 @@ mod tests; use crate::cell::UnsafeCell; +use crate::hint; use crate::ops::{Deref, DerefMut}; -use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; +use crate::sync::atomic::{AtomicBool, Ordering}; #[derive(Default)] pub struct SpinMutex { @@ -32,7 +33,7 @@ impl SpinMutex { match self.try_lock() { None => { while self.lock.load(Ordering::Relaxed) { - spin_loop_hint() + hint::spin_loop() } } Some(guard) => return guard, diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 3615a8a5ee8b0..f4c67b225e6e1 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -9,6 +9,14 @@ use crate::process; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `ExitStatusExt` trait, + /// which allows potentially adding more trait methods in the future. + #[stable(feature = "none", since = "1.51.0")] + pub trait Sealed {} +} + /// Unix-specific extensions to the [`process::Command`] builder. #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { @@ -163,18 +171,48 @@ impl CommandExt for process::Command { } /// Unix-specific extensions to [`process::ExitStatus`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { +pub trait ExitStatusExt: private::Sealed { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; /// If the process was terminated by a signal, returns that signal. + /// + /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`. #[stable(feature = "rust1", since = "1.0.0")] fn signal(&self) -> Option; + + /// If the process was terminated by a signal, says whether it dumped core. + #[unstable(feature = "unix_process_wait_more", issue = "80695")] + fn core_dumped(&self) -> bool; + + /// If the process was stopped by a signal, returns that signal. + /// + /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from + /// a `wait` system call which was passed `WUNTRACED`, was then converted into an `ExitStatus`. + #[unstable(feature = "unix_process_wait_more", issue = "80695")] + fn stopped_signal(&self) -> Option; + + /// Whether the process was continued from a stopped status. + /// + /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call + /// which was passed `WCONTINUED`, was then converted into an `ExitStatus`. + #[unstable(feature = "unix_process_wait_more", issue = "80695")] + fn continued(&self) -> bool; + + /// Returns the underlying raw `wait` status. + #[unstable(feature = "unix_process_wait_more", issue = "80695")] + fn into_raw(self) -> i32; } +#[stable(feature = "none", since = "1.51.0")] +impl private::Sealed for process::ExitStatus {} + #[stable(feature = "rust1", since = "1.0.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: i32) -> Self { @@ -184,6 +222,22 @@ impl ExitStatusExt for process::ExitStatus { fn signal(&self) -> Option { self.as_inner().signal() } + + fn core_dumped(&self) -> bool { + self.as_inner().core_dumped() + } + + fn stopped_signal(&self) -> Option { + self.as_inner().stopped_signal() + } + + fn continued(&self) -> bool { + self.as_inner().continued() + } + + fn into_raw(self) -> i32 { + self.as_inner().into_raw().into() + } } #[stable(feature = "process_extensions", since = "1.2.0")] diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index b64636c3f3d15..0d4703d7f503a 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -245,6 +245,50 @@ impl ExitStatus { pub fn signal(&self) -> Option { None } + + // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al. + // I infer from the implementation of `success`, `code` and `signal` above that these are not + // available on Fuchsia. + // + // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many + // other things from std::os::unix) properly. This veneer is always going to be a bodge. So + // while I don't know if these implementations are actually correct, I think they will do for + // now at least. + pub fn core_dumped(&self) -> bool { + false + } + pub fn stopped_signal(&self) -> Option { + None + } + pub fn continued(&self) -> bool { + false + } + + pub fn into_raw(&self) -> c_int { + // We don't know what someone who calls into_raw() will do with this value, but it should + // have the conventional Unix representation. Despite the fact that this is not + // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the + // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every + // Unix.) + // + // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may + // do their own shifting and masking, or even pass the status to another computer running a + // different Unix variant. + // + // The other view would be to say that the caller on Fuchsia ought to know that `into_raw` + // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is + // not possible here becaause we must return a c_int because that's what Unix (including + // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't + // necessarily fit. + // + // It seems to me that that the right answer would be to provide std::os::fuchsia with its + // own ExitStatusExt, rather that trying to provide a not very convincing imitation of + // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But + // fixing this up that is beyond the scope of my efforts now. + let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255."); + let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8; + wait_status_as_if_unix + } } /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index a590c74435639..945b43678a919 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -479,7 +479,23 @@ impl ExitStatus { } pub fn signal(&self) -> Option { - if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } + if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } + } + + pub fn core_dumped(&self) -> bool { + libc::WIFSIGNALED(self.0) && libc::WCOREDUMP(self.0) + } + + pub fn stopped_signal(&self) -> Option { + if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None } + } + + pub fn continued(&self) -> bool { + libc::WIFCONTINUED(self.0) + } + + pub fn into_raw(&self) -> c_int { + self.0 } } diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 61e4c6a1d1718..7a92381d6609b 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -7,6 +7,14 @@ use crate::process; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `ExitStatusExt` trait, + /// which allows potentially adding more trait methods in the future. + #[stable(feature = "none", since = "1.51.0")] + pub trait Sealed {} +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { @@ -73,8 +81,11 @@ impl IntoRawHandle for process::ChildStderr { } /// Windows-specific extensions to [`process::ExitStatus`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "exit_status_from", since = "1.12.0")] -pub trait ExitStatusExt { +pub trait ExitStatusExt: private::Sealed { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] @@ -88,6 +99,9 @@ impl ExitStatusExt for process::ExitStatus { } } +#[stable(feature = "none", since = "1.51.0")] +impl private::Sealed for process::ExitStatus {} + /// Windows-specific extensions to the [`process::Command`] builder. #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 5d65f960fcd39..0d004a516f594 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1186,32 +1186,37 @@ impl fmt::Debug for Thread { /// the [`Error`](crate::error::Error) trait. /// /// Thus, a sensible way to handle a thread panic is to either: -/// 1. `unwrap` the `Result`, propagating the panic +/// +/// 1. propagate the panic with [`std::panic::resume_unwind`] /// 2. or in case the thread is intended to be a subsystem boundary /// that is supposed to isolate system-level failures, -/// match on the `Err` variant and handle the panic in an appropriate way. +/// match on the `Err` variant and handle the panic in an appropriate way /// /// A thread that completes without panicking is considered to exit successfully. /// /// # Examples /// +/// Matching on the result of a joined thread: +/// /// ```no_run -/// use std::thread; -/// use std::fs; +/// use std::{fs, thread, panic}; /// /// fn copy_in_thread() -> thread::Result<()> { -/// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join() +/// thread::spawn(|| { +/// fs::copy("foo.txt", "bar.txt").unwrap(); +/// }).join() /// } /// /// fn main() { /// match copy_in_thread() { -/// Ok(_) => println!("this is fine"), -/// Err(_) => println!("thread panicked"), +/// Ok(_) => println!("copy succeeded"), +/// Err(e) => panic::resume_unwind(e), /// } /// } /// ``` /// /// [`Result`]: crate::result::Result +/// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] pub type Result = crate::result::Result>; diff --git a/src/doc/book b/src/doc/book index 5bb44f8b5b0aa..ac57a0ddd23d1 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21 +Subproject commit ac57a0ddd23d173b26731ccf939f3ba729753275 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index ba34b8a968f95..ceec19e873be8 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit ba34b8a968f9531d38c4dc4411d5568b7c076bfe +Subproject commit ceec19e873be87c6ee5666b030c6bb612f889a96 diff --git a/src/doc/nomicon b/src/doc/nomicon index a5a48441d411f..a8584998eacde 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit a5a48441d411f61556b57d762b03d6874afe575d +Subproject commit a8584998eacdea7106a1dfafcbf6c1c06fcdf925 diff --git a/src/doc/reference b/src/doc/reference index b278478b76617..50af691f83893 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a +Subproject commit 50af691f838937c300b47812d0507c6d88c14f97 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1cce0737d6a7d..03e23af01f0b4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab +Subproject commit 03e23af01f0b4f83a3a513da280e1ca92587f2ec diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 0e7174e5b19d6..c270593cac741 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -31,6 +31,15 @@ LL | struct TupleStruct(S, T); ... LL | TupleStruct(_) = TupleStruct(1, 2); | ^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | TupleStruct(_, _) = TupleStruct(1, 2); + | ^^^ +help: use `..` to ignore all fields + | +LL | TupleStruct(..) = TupleStruct(1, 2); + | ^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -49,6 +58,15 @@ LL | SingleVariant(S, T) ... LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); + | ^^^ +help: use `..` to ignore all fields + | +LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2); + | ^^ error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index a3610099294da..832eba6972213 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -6,6 +6,11 @@ LL | Apple(String, String), ... LL | Fruit::Apple(a) => {}, | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Fruit::Apple(a, _) => {}, + | ^^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:12:9 @@ -34,7 +39,7 @@ LL | Orange((String, String)), LL | Fruit::Orange(a, b) => {}, | ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2 | -help: missing parenthesis +help: missing parentheses | LL | Fruit::Orange((a, b)) => {}, | ^ ^ @@ -48,7 +53,7 @@ LL | Banana(()), LL | Fruit::Banana() => {}, | ^^^^^^^^^^^^^^^ expected 1 field, found 0 | -help: missing parenthesis +help: missing parentheses | LL | Fruit::Banana(()) => {}, | ^ ^ diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 6e8ea6bf618f2..9bdbf0bf9f40d 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -17,6 +17,15 @@ LL | struct P(T); // 1 type parameter wanted ... LL | let P() = U {}; | ^^^ expected 1 field, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | let P(_) = U {}; + | ^ +help: use `..` to ignore all fields + | +LL | let P(..) = U {}; + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr index 0a9c868af7af8..a1e8ec1677db5 100644 --- a/src/test/ui/issues/issue-72574-2.stderr +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -26,6 +26,11 @@ LL | struct Binder(i32, i32, i32); ... LL | Binder(_a, _x @ ..) => {} | ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Binder(_a, _x @ .., _) => {} + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index c2298d6fbbf02..37839482b31a2 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -6,6 +6,15 @@ LL | Rgb(usize, usize, usize), ... LL | Color::Rgb(_, _) => { } | ^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Color::Rgb(_, _, _) => { } + | ^^^ +help: use `..` to ignore all fields + | +LL | Color::Rgb(..) => { } + | ^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr index cbc90b5397d8b..f7644c19ea0d9 100644 --- a/src/test/ui/pattern/issue-74539.stderr +++ b/src/test/ui/pattern/issue-74539.stderr @@ -26,6 +26,11 @@ LL | A(u8, u8), ... LL | E::A(x @ ..) => { | ^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::A(x @ .., _) => { + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs new file mode 100644 index 0000000000000..ed852a47bb4ee --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -0,0 +1,55 @@ +struct S(i32, f32); +enum E { + S(i32, f32), +} +struct Point4(i32, i32, i32, i32); + +fn main() { + match S(0, 1.0) { + S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + } + match S(0, 1.0) { + S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match S(0, 1.0) { + S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + + match E::S(0, 1.0) { + E::S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + } + match E::S(0, 1.0) { + E::S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match E::S(0, 1.0) { + E::S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match E::S(0, 1.0) { + E::S => {} + //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S` + //~| HELP use the tuple variant pattern syntax instead + } + + match Point4(0, 1, 2, 3) { + Point4( a , _ ) => {} + //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore the rest of the fields + } +} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr new file mode 100644 index 0000000000000..76323d9a7bf56 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -0,0 +1,131 @@ +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` + --> $DIR/pat-tuple-underfield.rs:44:9 + | +LL | S(i32, f32), + | ----------- `E::S` defined here +... +LL | E::S => {} + | ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:9:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S(x) => {} + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(x, _) => {} + | ^^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:14:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S(_) => {} + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ^^^ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ^^ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:20:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S() => {} + | ^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ^^^^ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:27:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S(x) => {} + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(x, _) => {} + | ^^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:32:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S(_) => {} + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ^^^ +help: use `..` to ignore all fields + | +LL | E::S(..) => {} + | ^^ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:38:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S() => {} + | ^^^^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ^^^^ +help: use `..` to ignore all fields + | +LL | E::S(..) => {} + | ^^ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields + --> $DIR/pat-tuple-underfield.rs:50:9 + | +LL | struct Point4(i32, i32, i32, i32); + | ---------------------------------- tuple struct defined here +... +LL | Point4( a , _ ) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 4 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Point4( a , _ , _, _) => {} + | ^^^^^^ +help: use `..` to ignore the rest of the fields + | +LL | Point4( a , _ , ..) => {} + | ^^^^ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0023, E0532. +For more information about an error, try `rustc --explain E0023`.