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:
bors 2023-05-25 06:02:11 +00:00
commit 0b011b7b7e
13 changed files with 313 additions and 17 deletions

View File

@ -102,21 +102,27 @@ pub mod unord;
pub use ena::undo_log;
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> {
/// Forgets the function which prevents it from running.
/// Ensure that the function owns no memory, otherwise it will be leaked.
pub struct OnDrop<F: FnOnce()>(Option<F>);
impl<F: FnOnce()> OnDrop<F> {
/// Disables on-drop call.
#[inline]
pub fn disable(self) {
std::mem::forget(self);
pub fn disable(mut self) {
self.0.take();
}
}
impl<F: Fn()> Drop for OnDrop<F> {
impl<F: FnOnce()> Drop for OnDrop<F> {
#[inline]
fn drop(&mut self) {
(self.0)();
if let Some(f) = self.0.take() {
f();
}
}
}

View File

@ -7,8 +7,8 @@ use std::{
};
use crate::{
defer,
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
OnDrop,
};
#[test]
@ -66,7 +66,7 @@ fn boxed() {
fn drop_drops() {
let flag = Arc::new(AtomicBool::new(false));
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, |_| &[]);

View File

@ -3,9 +3,9 @@ use crate::util;
use rustc_ast::token;
use rustc_ast::{self as ast, LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::OnDrop;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorGuaranteed, Handler};
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 || {
let r = {
let _sess_abort_error = OnDrop(|| {
let _sess_abort_error = defer(|| {
compiler.sess.finish_diagnostics(registry);
});

View File

@ -78,7 +78,7 @@ where
{
TLV.with(|tlv| {
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()
})
}

View File

@ -340,6 +340,8 @@ mir_build_uncovered = {$count ->
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
} 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}
.pattern_ty = the matched value is of type `{$pattern_ty}`

View File

@ -781,6 +781,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub interpreted_as_const: Option<InterpretedAsConst>,
#[subdiagnostic]
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
#[note(mir_build_privately_uninhabited)]
pub witness_1_is_privately_uninhabited: Option<()>,
#[note(mir_build_pattern_ty)]
pub _p: (),
pub pattern_ty: Ty<'tcx>,

View File

@ -479,12 +479,30 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
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 {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform,
interpreted_as_const,
witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
_p: (),
pattern_ty,
let_suggestion,

View File

@ -22,7 +22,7 @@ use {
rustc_data_structures::fx::FxHashSet,
rustc_data_structures::sync::Lock,
rustc_data_structures::sync::Lrc,
rustc_data_structures::{jobserver, OnDrop},
rustc_data_structures::{defer, jobserver},
rustc_span::DUMMY_SP,
std::iter,
std::process,
@ -530,7 +530,7 @@ fn remove_cycle<D: DepKind>(
/// all active queries for cycles before finally resuming all the waiters at once.
#[cfg(parallel_compiler)]
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");
process::abort();
});

View File

@ -4,7 +4,7 @@ use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("macos", arch);
base.cpu = "apple-a14".into();
base.cpu = "apple-m1".into();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.

View File

@ -319,6 +319,264 @@ impl<T> [T] {
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
/// index.
///

View File

@ -14,6 +14,7 @@ LL | enum Either<A, B> {
LL | A(A),
LL | B(inner::Wrapper<B>),
| - 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<(), !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|

View File

@ -16,7 +16,9 @@ struct NotSoSecretlyEmpty {
}
enum Foo {
//~^ NOTE `Foo` defined here
A(foo::SecretlyEmpty),
//~^ NOTE not covered
B(foo::NotSoSecretlyEmpty),
C(NotSoSecretlyEmpty),
D(u32, u32),
@ -27,4 +29,9 @@ fn main() {
let Foo::D(_y, _z) = x;
//~^ ERROR refutable pattern in local binding
//~| `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`
}

View File

@ -1,5 +1,5 @@
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;
| ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
@ -11,8 +11,10 @@ note: `Foo` defined here
|
LL | enum Foo {
| ^^^
LL |
LL | A(foo::SecretlyEmpty),
| - 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`
help: you might want to use `let else` to handle the variant that isn't matched
|