Skip to content

Rollup of 4 pull requests #111933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 25, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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))
}

pub struct OnDrop<F: FnOnce()>(Option<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.
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();
}
}
}

4 changes: 2 additions & 2 deletions compiler/rustc_data_structures/src/owned_slice/tests.rs
Original file line number Diff line number Diff line change
@@ -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, |_| &[]);

4 changes: 2 additions & 2 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
@@ -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);
});

2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context/tls.rs
Original file line number Diff line number Diff line change
@@ -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()
})
}
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
@@ -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}`

2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
@@ -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>,
18 changes: 18 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 2 additions & 2 deletions compiler/rustc_query_system/src/query/job.rs
Original file line number Diff line number Diff line change
@@ -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();
});
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
Original file line number Diff line number Diff line change
@@ -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.
258 changes: 258 additions & 0 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
///
1 change: 1 addition & 0 deletions tests/ui/never_type/exhaustive_patterns.stderr
Original file line number Diff line number Diff line change
@@ -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
|
7 changes: 7 additions & 0 deletions tests/ui/uninhabited/uninhabited-irrefutable.rs
Original file line number Diff line number Diff line change
@@ -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`
}
4 changes: 3 additions & 1 deletion tests/ui/uninhabited/uninhabited-irrefutable.stderr
Original file line number Diff line number Diff line change
@@ -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
|