Auto merge of #111933 - matthiaskrgr:rollup-m10k3ts, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #95198 (Add slice::{split_,}{first,last}_chunk{,_mut}) - #109899 (Use apple-m1 as target CPU for aarch64-apple-darwin.) - #111624 (Emit diagnostic for privately uninhabited uncovered witnesses.) - #111875 (Don't leak the function that is called on drop) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0b011b7b7e
13 changed files with 313 additions and 17 deletions
|
@ -102,21 +102,27 @@ pub mod unord;
|
||||||
pub use ena::undo_log;
|
pub use ena::undo_log;
|
||||||
pub use ena::unify;
|
pub use ena::unify;
|
||||||
|
|
||||||
pub struct OnDrop<F: Fn()>(pub F);
|
/// Returns a structure that calls `f` when dropped.
|
||||||
|
pub fn defer<F: FnOnce()>(f: F) -> OnDrop<F> {
|
||||||
|
OnDrop(Some(f))
|
||||||
|
}
|
||||||
|
|
||||||
impl<F: Fn()> OnDrop<F> {
|
pub struct OnDrop<F: FnOnce()>(Option<F>);
|
||||||
/// Forgets the function which prevents it from running.
|
|
||||||
/// Ensure that the function owns no memory, otherwise it will be leaked.
|
impl<F: FnOnce()> OnDrop<F> {
|
||||||
|
/// Disables on-drop call.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable(self) {
|
pub fn disable(mut self) {
|
||||||
std::mem::forget(self);
|
self.0.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fn()> Drop for OnDrop<F> {
|
impl<F: FnOnce()> Drop for OnDrop<F> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
(self.0)();
|
if let Some(f) = self.0.take() {
|
||||||
|
f();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
defer,
|
||||||
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
|
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
|
||||||
OnDrop,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -66,7 +66,7 @@ fn boxed() {
|
||||||
fn drop_drops() {
|
fn drop_drops() {
|
||||||
let flag = Arc::new(AtomicBool::new(false));
|
let flag = Arc::new(AtomicBool::new(false));
|
||||||
let flag_prime = Arc::clone(&flag);
|
let flag_prime = Arc::clone(&flag);
|
||||||
let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed));
|
let d = defer(move || flag_prime.store(true, atomic::Ordering::Relaxed));
|
||||||
|
|
||||||
let slice = slice_owned(d, |_| &[]);
|
let slice = slice_owned(d, |_| &[]);
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ use crate::util;
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
use rustc_ast::{self as ast, LitKind, MetaItemKind};
|
use rustc_ast::{self as ast, LitKind, MetaItemKind};
|
||||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||||
|
use rustc_data_structures::defer;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_data_structures::OnDrop;
|
|
||||||
use rustc_errors::registry::Registry;
|
use rustc_errors::registry::Registry;
|
||||||
use rustc_errors::{ErrorGuaranteed, Handler};
|
use rustc_errors::{ErrorGuaranteed, Handler};
|
||||||
use rustc_lint::LintStore;
|
use rustc_lint::LintStore;
|
||||||
|
@ -325,7 +325,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
||||||
|
|
||||||
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
|
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
|
||||||
let r = {
|
let r = {
|
||||||
let _sess_abort_error = OnDrop(|| {
|
let _sess_abort_error = defer(|| {
|
||||||
compiler.sess.finish_diagnostics(registry);
|
compiler.sess.finish_diagnostics(registry);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ where
|
||||||
{
|
{
|
||||||
TLV.with(|tlv| {
|
TLV.with(|tlv| {
|
||||||
let old = tlv.replace(erase(context));
|
let old = tlv.replace(erase(context));
|
||||||
let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
|
let _reset = rustc_data_structures::defer(move || tlv.set(old));
|
||||||
f()
|
f()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,6 +340,8 @@ mir_build_uncovered = {$count ->
|
||||||
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
|
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
|
||||||
} not covered
|
} not covered
|
||||||
|
|
||||||
|
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||||
|
|
||||||
mir_build_pattern_not_covered = refutable pattern in {$origin}
|
mir_build_pattern_not_covered = refutable pattern in {$origin}
|
||||||
.pattern_ty = the matched value is of type `{$pattern_ty}`
|
.pattern_ty = the matched value is of type `{$pattern_ty}`
|
||||||
|
|
||||||
|
|
|
@ -781,6 +781,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
|
||||||
pub interpreted_as_const: Option<InterpretedAsConst>,
|
pub interpreted_as_const: Option<InterpretedAsConst>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
|
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
|
||||||
|
#[note(mir_build_privately_uninhabited)]
|
||||||
|
pub witness_1_is_privately_uninhabited: Option<()>,
|
||||||
#[note(mir_build_pattern_ty)]
|
#[note(mir_build_pattern_ty)]
|
||||||
pub _p: (),
|
pub _p: (),
|
||||||
pub pattern_ty: Ty<'tcx>,
|
pub pattern_ty: Ty<'tcx>,
|
||||||
|
|
|
@ -479,12 +479,30 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
||||||
AdtDefinedHere { adt_def_span, ty, variants }
|
AdtDefinedHere { adt_def_span, ty, variants }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Emit an extra note if the first uncovered witness is
|
||||||
|
// visibly uninhabited anywhere in the current crate.
|
||||||
|
let witness_1_is_privately_uninhabited =
|
||||||
|
if cx.tcx.features().exhaustive_patterns
|
||||||
|
&& let Some(witness_1) = witnesses.get(0)
|
||||||
|
&& let ty::Adt(adt, substs) = witness_1.ty().kind()
|
||||||
|
&& adt.is_enum()
|
||||||
|
&& let Constructor::Variant(variant_index) = witness_1.ctor()
|
||||||
|
{
|
||||||
|
let variant = adt.variant(*variant_index);
|
||||||
|
let inhabited = variant.inhabited_predicate(cx.tcx, *adt).subst(cx.tcx, substs);
|
||||||
|
assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module));
|
||||||
|
!inhabited.apply_ignore_module(cx.tcx, cx.param_env)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
|
self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
|
||||||
span: pat.span,
|
span: pat.span,
|
||||||
origin,
|
origin,
|
||||||
uncovered: Uncovered::new(pat.span, &cx, witnesses),
|
uncovered: Uncovered::new(pat.span, &cx, witnesses),
|
||||||
inform,
|
inform,
|
||||||
interpreted_as_const,
|
interpreted_as_const,
|
||||||
|
witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
|
||||||
_p: (),
|
_p: (),
|
||||||
pattern_ty,
|
pattern_ty,
|
||||||
let_suggestion,
|
let_suggestion,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use {
|
||||||
rustc_data_structures::fx::FxHashSet,
|
rustc_data_structures::fx::FxHashSet,
|
||||||
rustc_data_structures::sync::Lock,
|
rustc_data_structures::sync::Lock,
|
||||||
rustc_data_structures::sync::Lrc,
|
rustc_data_structures::sync::Lrc,
|
||||||
rustc_data_structures::{jobserver, OnDrop},
|
rustc_data_structures::{defer, jobserver},
|
||||||
rustc_span::DUMMY_SP,
|
rustc_span::DUMMY_SP,
|
||||||
std::iter,
|
std::iter,
|
||||||
std::process,
|
std::process,
|
||||||
|
@ -530,7 +530,7 @@ fn remove_cycle<D: DepKind>(
|
||||||
/// all active queries for cycles before finally resuming all the waiters at once.
|
/// all active queries for cycles before finally resuming all the waiters at once.
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Registry) {
|
pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Registry) {
|
||||||
let on_panic = OnDrop(|| {
|
let on_panic = defer(|| {
|
||||||
eprintln!("deadlock handler panicked, aborting process");
|
eprintln!("deadlock handler panicked, aborting process");
|
||||||
process::abort();
|
process::abort();
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
|
||||||
pub fn target() -> Target {
|
pub fn target() -> Target {
|
||||||
let arch = Arch::Arm64;
|
let arch = Arch::Arm64;
|
||||||
let mut base = opts("macos", arch);
|
let mut base = opts("macos", arch);
|
||||||
base.cpu = "apple-a14".into();
|
base.cpu = "apple-m1".into();
|
||||||
base.max_atomic_width = Some(128);
|
base.max_atomic_width = Some(128);
|
||||||
|
|
||||||
// FIXME: The leak sanitizer currently fails the tests, see #88132.
|
// FIXME: The leak sanitizer currently fails the tests, see #88132.
|
||||||
|
|
|
@ -319,6 +319,264 @@ impl<T> [T] {
|
||||||
if let [.., last] = self { Some(last) } else { None }
|
if let [.., last] = self { Some(last) } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the first `N` elements of the slice, or `None` if it has fewer than `N` elements.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let u = [10, 40, 30];
|
||||||
|
/// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>());
|
||||||
|
///
|
||||||
|
/// let v: &[i32] = &[10];
|
||||||
|
/// assert_eq!(None, v.first_chunk::<2>());
|
||||||
|
///
|
||||||
|
/// let w: &[i32] = &[];
|
||||||
|
/// assert_eq!(Some(&[]), w.first_chunk::<0>());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn first_chunk<const N: usize>(&self) -> Option<&[T; N]> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// and do not let the reference outlive the slice.
|
||||||
|
Some(unsafe { &*(self.as_ptr() as *const [T; N]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the first `N` elements of the slice,
|
||||||
|
/// or `None` if it has fewer than `N` elements.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &mut [0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some(first) = x.first_chunk_mut::<2>() {
|
||||||
|
/// first[0] = 5;
|
||||||
|
/// first[1] = 4;
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(x, &[5, 4, 2]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// do not let the reference outlive the slice,
|
||||||
|
// and require exclusive access to the entire slice to mutate the chunk.
|
||||||
|
Some(unsafe { &mut *(self.as_mut_ptr() as *mut [T; N]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first `N` elements of the slice and the remainder,
|
||||||
|
/// or `None` if it has fewer than `N` elements.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &[0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some((first, elements)) = x.split_first_chunk::<2>() {
|
||||||
|
/// assert_eq!(first, &[0, 1]);
|
||||||
|
/// assert_eq!(elements, &[2]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the split.
|
||||||
|
let (first, tail) = unsafe { self.split_at_unchecked(N) };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// and do not let the references outlive the slice.
|
||||||
|
Some((unsafe { &*(first.as_ptr() as *const [T; N]) }, tail))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the first `N` elements of the slice and the remainder,
|
||||||
|
/// or `None` if it has fewer than `N` elements.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &mut [0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() {
|
||||||
|
/// first[0] = 3;
|
||||||
|
/// first[1] = 4;
|
||||||
|
/// elements[0] = 5;
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(x, &[3, 4, 5]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn split_first_chunk_mut<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
) -> Option<(&mut [T; N], &mut [T])> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the split.
|
||||||
|
let (first, tail) = unsafe { self.split_at_mut_unchecked(N) };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// do not let the reference outlive the slice,
|
||||||
|
// and enforce exclusive mutability of the chunk by the split.
|
||||||
|
Some((unsafe { &mut *(first.as_mut_ptr() as *mut [T; N]) }, tail))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the last `N` elements of the slice and the remainder,
|
||||||
|
/// or `None` if it has fewer than `N` elements.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &[0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some((last, elements)) = x.split_last_chunk::<2>() {
|
||||||
|
/// assert_eq!(last, &[1, 2]);
|
||||||
|
/// assert_eq!(elements, &[0]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the split.
|
||||||
|
let (init, last) = unsafe { self.split_at_unchecked(self.len() - N) };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// and do not let the references outlive the slice.
|
||||||
|
Some((unsafe { &*(last.as_ptr() as *const [T; N]) }, init))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &mut [0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some((last, elements)) = x.split_last_chunk_mut::<2>() {
|
||||||
|
/// last[0] = 3;
|
||||||
|
/// last[1] = 4;
|
||||||
|
/// elements[0] = 5;
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(x, &[5, 3, 4]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn split_last_chunk_mut<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
) -> Option<(&mut [T; N], &mut [T])> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the split.
|
||||||
|
let (init, last) = unsafe { self.split_at_mut_unchecked(self.len() - N) };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// do not let the reference outlive the slice,
|
||||||
|
// and enforce exclusive mutability of the chunk by the split.
|
||||||
|
Some((unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }, init))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the last element of the slice, or `None` if it is empty.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let u = [10, 40, 30];
|
||||||
|
/// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>());
|
||||||
|
///
|
||||||
|
/// let v: &[i32] = &[10];
|
||||||
|
/// assert_eq!(None, v.last_chunk::<2>());
|
||||||
|
///
|
||||||
|
/// let w: &[i32] = &[];
|
||||||
|
/// assert_eq!(Some(&[]), w.last_chunk::<0>());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the slice.
|
||||||
|
// FIXME: Without const traits, we need this instead of `get_unchecked`.
|
||||||
|
let last = unsafe { self.split_at_unchecked(self.len() - N).1 };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// and do not let the references outlive the slice.
|
||||||
|
Some(unsafe { &*(last.as_ptr() as *const [T; N]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable pointer to the last item in the slice.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(slice_first_last_chunk)]
|
||||||
|
///
|
||||||
|
/// let x = &mut [0, 1, 2];
|
||||||
|
///
|
||||||
|
/// if let Some(last) = x.last_chunk_mut::<2>() {
|
||||||
|
/// last[0] = 10;
|
||||||
|
/// last[1] = 20;
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(x, &[0, 10, 20]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")]
|
||||||
|
#[inline]
|
||||||
|
pub const fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
|
||||||
|
if self.len() < N {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// SAFETY: We manually verified the bounds of the slice.
|
||||||
|
// FIXME: Without const traits, we need this instead of `get_unchecked`.
|
||||||
|
let last = unsafe { self.split_at_mut_unchecked(self.len() - N).1 };
|
||||||
|
|
||||||
|
// SAFETY: We explicitly check for the correct number of elements,
|
||||||
|
// do not let the reference outlive the slice,
|
||||||
|
// and require exclusive access to the entire slice to mutate the chunk.
|
||||||
|
Some(unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to an element or subslice depending on the type of
|
/// Returns a reference to an element or subslice depending on the type of
|
||||||
/// index.
|
/// index.
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,6 +14,7 @@ LL | enum Either<A, B> {
|
||||||
LL | A(A),
|
LL | A(A),
|
||||||
LL | B(inner::Wrapper<B>),
|
LL | B(inner::Wrapper<B>),
|
||||||
| - not covered
|
| - not covered
|
||||||
|
= note: pattern `Either::B(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||||
= note: the matched value is of type `Either<(), !>`
|
= note: the matched value is of type `Either<(), !>`
|
||||||
help: you might want to use `if let` to ignore the variant that isn't matched
|
help: you might want to use `if let` to ignore the variant that isn't matched
|
||||||
|
|
|
|
||||||
|
|
|
@ -16,7 +16,9 @@ struct NotSoSecretlyEmpty {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
|
//~^ NOTE `Foo` defined here
|
||||||
A(foo::SecretlyEmpty),
|
A(foo::SecretlyEmpty),
|
||||||
|
//~^ NOTE not covered
|
||||||
B(foo::NotSoSecretlyEmpty),
|
B(foo::NotSoSecretlyEmpty),
|
||||||
C(NotSoSecretlyEmpty),
|
C(NotSoSecretlyEmpty),
|
||||||
D(u32, u32),
|
D(u32, u32),
|
||||||
|
@ -27,4 +29,9 @@ fn main() {
|
||||||
let Foo::D(_y, _z) = x;
|
let Foo::D(_y, _z) = x;
|
||||||
//~^ ERROR refutable pattern in local binding
|
//~^ ERROR refutable pattern in local binding
|
||||||
//~| `Foo::A(_)` not covered
|
//~| `Foo::A(_)` not covered
|
||||||
|
//~| NOTE `let` bindings require an "irrefutable pattern"
|
||||||
|
//~| NOTE for more information
|
||||||
|
//~| NOTE pattern `Foo::A(_)` is currently uninhabited
|
||||||
|
//~| NOTE the matched value is of type `Foo`
|
||||||
|
//~| HELP you might want to use `let else`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0005]: refutable pattern in local binding
|
error[E0005]: refutable pattern in local binding
|
||||||
--> $DIR/uninhabited-irrefutable.rs:27:9
|
--> $DIR/uninhabited-irrefutable.rs:29:9
|
||||||
|
|
|
|
||||||
LL | let Foo::D(_y, _z) = x;
|
LL | let Foo::D(_y, _z) = x;
|
||||||
| ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
|
| ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
|
||||||
|
@ -11,8 +11,10 @@ note: `Foo` defined here
|
||||||
|
|
|
|
||||||
LL | enum Foo {
|
LL | enum Foo {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
LL |
|
||||||
LL | A(foo::SecretlyEmpty),
|
LL | A(foo::SecretlyEmpty),
|
||||||
| - not covered
|
| - not covered
|
||||||
|
= note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||||
= note: the matched value is of type `Foo`
|
= note: the matched value is of type `Foo`
|
||||||
help: you might want to use `let else` to handle the variant that isn't matched
|
help: you might want to use `let else` to handle the variant that isn't matched
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue