Auto merge of #81018 - m-ou-se:rollup-7202dc7, r=m-ou-se
Rollup of 17 pull requests Successful merges: - #79982 (Add missing methods to unix ExitStatusExt) - #80017 (Suggest `_` and `..` if a pattern has too few fields) - #80169 (Recommend panic::resume_unwind instead of panicking.) - #80217 (Add a `std::io::read_to_string` function) - #80444 (Add as_ref and as_mut methods for Bound) - #80567 (Add Iterator::intersperse_with) - #80829 (Get rid of `DepConstructor`) - #80895 (Fix handling of malicious Readers in read_to_end) - #80966 (Deprecate atomic::spin_loop_hint in favour of hint::spin_loop) - #80969 (Use better ICE message when no MIR is available) - #80972 (Remove unstable deprecated Vec::remove_item) - #80973 (Update books) - #80980 (Fixed incorrect doc comment) - #80981 (Fix -Cpasses=list and llvm version print with -vV) - #80985 (Fix stabilisation version of slice_strip) - #80990 (llvm: Remove the unused context from CreateDebugLocation) - #80991 (Fix formatting specifiers doc links) Failed merges: - #80944 (Use Option::map_or instead of `.map(..).unwrap_or(..)`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e38fb306b7
@ -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,
|
||||
|
@ -2102,7 +2102,6 @@ extern "C" {
|
||||
);
|
||||
|
||||
pub fn LLVMRustDIBuilderCreateDebugLocation(
|
||||
Context: &'a Context,
|
||||
Line: c_uint,
|
||||
Column: c_uint,
|
||||
Scope: &'a DIScope,
|
||||
|
@ -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<getopts::Matches> {
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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<MDNode>(Scope),
|
||||
unwrapDIPtr<MDNode>(InlinedAt));
|
||||
|
||||
|
@ -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<DepKind, ()> {
|
||||
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<DepKind>;
|
||||
|
||||
// We keep a lot of `DepNode`s in memory during compilation. It's not
|
||||
|
@ -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<DepKind>;
|
||||
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>(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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -1953,27 +1953,6 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Vec<T, A> {
|
||||
/// 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<V>(&mut self, item: &V) -> Option<T>
|
||||
where
|
||||
T: PartialEq<V>,
|
||||
{
|
||||
let pos = self.iter().position(|x| *x == *item)?;
|
||||
Some(self.remove(pos))
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal methods and functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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");
|
||||
/// ```
|
||||
|
@ -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<I: Iterator>
|
||||
@ -40,37 +43,146 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn fold<B, F>(mut self, init: B, mut f: F) -> B
|
||||
fn fold<B, F>(self, init: B, f: F) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
let mut accum = init;
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
let element = &self.separator;
|
||||
|
||||
self.iter.fold(accum, |mut accum, x| {
|
||||
accum = f(accum, element.clone());
|
||||
accum = f(accum, x);
|
||||
accum
|
||||
})
|
||||
let separator = self.separator;
|
||||
intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<I, G>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
separator: G,
|
||||
iter: Peekable<I>,
|
||||
needs_sep: bool,
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
|
||||
impl<I, G> crate::fmt::Debug for IntersperseWith<I, G>
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
|
||||
impl<I, G> crate::clone::Clone for IntersperseWith<I, G>
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, G> IntersperseWith<I, G>
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
|
||||
impl<I, G> Iterator for IntersperseWith<I, G>
|
||||
where
|
||||
I: Iterator,
|
||||
G: FnMut() -> I::Item,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
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<B, F>(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<usize>) {
|
||||
intersperse_size_hint(&self.iter, self.needs_sep)
|
||||
}
|
||||
}
|
||||
|
||||
fn intersperse_size_hint<I>(iter: &I, needs_sep: bool) -> (usize, Option<usize>)
|
||||
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<I, B, F, G>(
|
||||
mut iter: Peekable<I>,
|
||||
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
|
||||
})
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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::<String>();
|
||||
/// assert_eq!(hello, "Hello World");
|
||||
/// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>();
|
||||
/// 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<Self>
|
||||
@ -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::<String>();
|
||||
/// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
|
||||
fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
|
||||
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.
|
||||
///
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -678,6 +678,29 @@ pub enum Bound<T> {
|
||||
Unbounded,
|
||||
}
|
||||
|
||||
#[unstable(feature = "bound_as_ref", issue = "80996")]
|
||||
impl<T> Bound<T> {
|
||||
/// Converts from `&Bound<T>` 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<T>` 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<T: Clone> Bound<&T> {
|
||||
/// Map a `Bound<&T>` to a `Bound<T>` by cloning the contents of the bound.
|
||||
///
|
||||
|
@ -1877,7 +1877,7 @@ impl<T> [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<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Option<&[T]>
|
||||
where
|
||||
T: PartialEq,
|
||||
@ -1911,7 +1911,7 @@ impl<T> [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<P: SlicePattern<Item = T> + ?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<T> SlicePattern for [T] {
|
||||
type Item = T;
|
||||
|
||||
@ -3333,7 +3333,7 @@ impl<T> SlicePattern for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "slice_strip", since = "1.50.0")]
|
||||
#[stable(feature = "slice_strip", since = "1.51.0")]
|
||||
impl<T, const N: usize> SlicePattern for [T; N] {
|
||||
type Item = T;
|
||||
|
||||
|
@ -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<T> fmt::Pointer for AtomicPtr<T> {
|
||||
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()
|
||||
}
|
||||
|
@ -3508,6 +3508,12 @@ pub fn extend_for_unit() {
|
||||
|
||||
#[test]
|
||||
fn test_intersperse() {
|
||||
let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
|
||||
assert_eq!(v, vec![]);
|
||||
|
||||
let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
|
||||
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::<i32>().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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
assert_eq!(r, vec![0, 200, 1, 400, 2]);
|
||||
}
|
||||
|
@ -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<F>(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
|
||||
@ -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<R: Read>(reader: &mut R) -> Result<String> {
|
||||
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
|
||||
|
@ -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<T> Spinlock<T> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<T> {
|
||||
@ -32,7 +33,7 @@ impl<T> SpinMutex<T> {
|
||||
match self.try_lock() {
|
||||
None => {
|
||||
while self.lock.load(Ordering::Relaxed) {
|
||||
spin_loop_hint()
|
||||
hint::spin_loop()
|
||||
}
|
||||
}
|
||||
Some(guard) => return guard,
|
||||
|
@ -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<i32>;
|
||||
|
||||
/// 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<i32>;
|
||||
|
||||
/// 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<i32> {
|
||||
self.as_inner().signal()
|
||||
}
|
||||
|
||||
fn core_dumped(&self) -> bool {
|
||||
self.as_inner().core_dumped()
|
||||
}
|
||||
|
||||
fn stopped_signal(&self) -> Option<i32> {
|
||||
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")]
|
||||
|
@ -245,6 +245,50 @@ impl ExitStatus {
|
||||
pub fn signal(&self) -> Option<i32> {
|
||||
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<i32> {
|
||||
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.
|
||||
|
@ -479,7 +479,23 @@ impl ExitStatus {
|
||||
}
|
||||
|
||||
pub fn signal(&self) -> Option<i32> {
|
||||
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<i32> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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<T>`, 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<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21
|
||||
Subproject commit ac57a0ddd23d173b26731ccf939f3ba729753275
|
@ -1 +1 @@
|
||||
Subproject commit ba34b8a968f9531d38c4dc4411d5568b7c076bfe
|
||||
Subproject commit ceec19e873be87c6ee5666b030c6bb612f889a96
|
@ -1 +1 @@
|
||||
Subproject commit a5a48441d411f61556b57d762b03d6874afe575d
|
||||
Subproject commit a8584998eacdea7106a1dfafcbf6c1c06fcdf925
|
@ -1 +1 @@
|
||||
Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a
|
||||
Subproject commit 50af691f838937c300b47812d0507c6d88c14f97
|
@ -1 +1 @@
|
||||
Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab
|
||||
Subproject commit 03e23af01f0b4f83a3a513da280e1ca92587f2ec
|
@ -31,6 +31,15 @@ LL | struct TupleStruct<S, T>(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
|
||||
|
@ -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(()) => {},
|
||||
| ^ ^
|
||||
|
@ -17,6 +17,15 @@ LL | struct P<T>(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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
55
src/test/ui/pattern/pat-tuple-underfield.rs
Normal file
55
src/test/ui/pattern/pat-tuple-underfield.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
131
src/test/ui/pattern/pat-tuple-underfield.stderr
Normal file
131
src/test/ui/pattern/pat-tuple-underfield.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user