Skip to content

Commit

Permalink
Auto merge of rust-lang#125552 - matthiaskrgr:rollup-f1yybpn, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#121377 (Stabilize `LazyCell` and `LazyLock`)
 - rust-lang#122986 (Fix c_char on AIX)
 - rust-lang#123803 (Fix `VecDeque::shrink_to` UB when `handle_alloc_error` unwinds.)
 - rust-lang#124080 (Some unstable changes to where opaque types get defined)
 - rust-lang#124667 (Stabilize `div_duration`)
 - rust-lang#125472 (tidy: validate LLVM component names in tests)
 - rust-lang#125523 (Exit the process a short time after entering our ctrl-c handler)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed May 25, 2024
2 parents 1ba35e9 + 0ded36f commit 0a59f11
Show file tree
Hide file tree
Showing 76 changed files with 590 additions and 222 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}

if let ConstContext::Static(_) = ccx.const_kind() {
err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
err.note("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`");
}

err
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
#![feature(lazy_cell)]
#![feature(lint_reasons)]
#![feature(macro_metavar_expr)]
#![feature(map_try_insert)]
Expand Down
17 changes: 8 additions & 9 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use std::process::{self, Command, Stdio};
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};
use std::time::{Instant, SystemTime};
use std::time::{Duration, Instant, SystemTime};
use time::OffsetDateTime;
use tracing::trace;

Expand Down Expand Up @@ -1502,14 +1502,13 @@ pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) {
pub fn install_ctrlc_handler() {
#[cfg(not(target_family = "wasm"))]
ctrlc::set_handler(move || {
// Indicate that we have been signaled to stop. If we were already signaled, exit
// immediately. In our interpreter loop we try to consult this value often, but if for
// whatever reason we don't get to that check or the cleanup we do upon finding that
// this bool has become true takes a long time, the exit here will promptly exit the
// process on the second Ctrl-C.
if CTRL_C_RECEIVED.swap(true, Ordering::Relaxed) {
std::process::exit(1);
}
// Indicate that we have been signaled to stop, then give the rest of the compiler a bit of
// time to check CTRL_C_RECEIVED and run its own shutdown logic, but after a short amount
// of time exit the process. This sleep+exit ensures that even if nobody is checking
// CTRL_C_RECEIVED, the compiler exits reasonably promptly.
CTRL_C_RECEIVED.store(true, Ordering::Relaxed);
std::thread::sleep(Duration::from_millis(100));
std::process::exit(1);
})
.expect("Unable to install ctrlc handler");
}
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![feature(lazy_cell)]
#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
#![allow(internal_features)]
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#![allow(internal_features)]
#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(lazy_cell)]

mod accepted;
mod builtin_attrs;
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ This API is completely unstable and subject to change.
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(lazy_cell)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_interface/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(decl_macro)]
#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(thread_spawn_unchecked)]
#![feature(try_blocks)]
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,10 +1316,8 @@ declare_lint! {
/// * If you are trying to perform a one-time initialization of a global:
/// * If the value can be computed at compile-time, consider using
/// const-compatible values (see [Constant Evaluation]).
/// * For more complex single-initialization cases, consider using a
/// third-party crate, such as [`lazy_static`] or [`once_cell`].
/// * If you are using the [nightly channel], consider the new
/// [`lazy`] module in the standard library.
/// * For more complex single-initialization cases, consider using
/// [`std::sync::LazyLock`].
/// * If you truly need a mutable global, consider using a [`static`],
/// which has a variety of options:
/// * Simple data types can be directly defined and mutated with an
Expand All @@ -1334,9 +1332,7 @@ declare_lint! {
/// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html
/// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
/// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics
/// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html
/// [`lazy_static`]: https://crates.io/crates/lazy_static
/// [`once_cell`]: https://crates.io/crates/once_cell
/// [`std::sync::LazyLock`]: https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html
/// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html
/// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
pub CONST_ITEM_MUTATION,
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_session/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(let_chains)]
#![feature(lazy_cell)]
#![feature(option_get_or_insert_default)]
#![feature(rustc_attrs)]
#![feature(map_many_mut)]
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2539,7 +2539,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref)
.eq(DefineOpaqueTypes::Yes, placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
})?;
Expand Down Expand Up @@ -2594,7 +2594,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self.infcx
.at(&obligation.cause, obligation.param_env)
.eq(
DefineOpaqueTypes::No,
DefineOpaqueTypes::Yes,
upcast_principal.map_bound(|trait_ref| {
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
}),
Expand Down Expand Up @@ -2631,7 +2631,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
nested.extend(
self.infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, source_projection, target_projection)
.eq(DefineOpaqueTypes::Yes, source_projection, target_projection)
.map_err(|_| SelectionError::Unimplemented)?
.into_obligations(),
);
Expand Down
4 changes: 4 additions & 0 deletions library/alloc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ rand_xorshift = "0.3.0"
name = "alloctests"
path = "tests/lib.rs"

[[test]]
name = "vec_deque_alloc_error"
path = "tests/vec_deque_alloc_error.rs"

[[bench]]
name = "allocbenches"
path = "benches/lib.rs"
Expand Down
66 changes: 65 additions & 1 deletion library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
// `head` and `len` are at most `isize::MAX` and `target_cap < self.capacity()`, so nothing can
// overflow.
let tail_outside = (target_cap + 1..=self.capacity()).contains(&(self.head + self.len));
// Used in the drop guard below.
let old_head = self.head;

if self.len == 0 {
self.head = 0;
Expand Down Expand Up @@ -1034,12 +1036,74 @@ impl<T, A: Allocator> VecDeque<T, A> {
}
self.head = new_head;
}
self.buf.shrink_to_fit(target_cap);

struct Guard<'a, T, A: Allocator> {
deque: &'a mut VecDeque<T, A>,
old_head: usize,
target_cap: usize,
}

impl<T, A: Allocator> Drop for Guard<'_, T, A> {
#[cold]
fn drop(&mut self) {
unsafe {
// SAFETY: This is only called if `buf.shrink_to_fit` unwinds,
// which is the only time it's safe to call `abort_shrink`.
self.deque.abort_shrink(self.old_head, self.target_cap)
}
}
}

let guard = Guard { deque: self, old_head, target_cap };

guard.deque.buf.shrink_to_fit(target_cap);

// Don't drop the guard if we didn't unwind.
mem::forget(guard);

debug_assert!(self.head < self.capacity() || self.capacity() == 0);
debug_assert!(self.len <= self.capacity());
}

/// Reverts the deque back into a consistent state in case `shrink_to` failed.
/// This is necessary to prevent UB if the backing allocator returns an error
/// from `shrink` and `handle_alloc_error` subsequently unwinds (see #123369).
///
/// `old_head` refers to the head index before `shrink_to` was called. `target_cap`
/// is the capacity that it was trying to shrink to.
unsafe fn abort_shrink(&mut self, old_head: usize, target_cap: usize) {
// Moral equivalent of self.head + self.len <= target_cap. Won't overflow
// because `self.len <= target_cap`.
if self.head <= target_cap - self.len {
// The deque's buffer is contiguous, so no need to copy anything around.
return;
}

// `shrink_to` already copied the head to fit into the new capacity, so this won't overflow.
let head_len = target_cap - self.head;
// `self.head > target_cap - self.len` => `self.len > target_cap - self.head =: head_len` so this must be positive.
let tail_len = self.len - head_len;

if tail_len <= cmp::min(head_len, self.capacity() - target_cap) {
// There's enough spare capacity to copy the tail to the back (because `tail_len < self.capacity() - target_cap`),
// and copying the tail should be cheaper than copying the head (because `tail_len <= head_len`).

unsafe {
// The old tail and the new tail can't overlap because the head slice lies between them. The
// head slice ends at `target_cap`, so that's where we copy to.
self.copy_nonoverlapping(0, target_cap, tail_len);
}
} else {
// Either there's not enough spare capacity to make the deque contiguous, or the head is shorter than the tail
// (and therefore hopefully cheaper to copy).
unsafe {
// The old and the new head slice can overlap, so we can't use `copy_nonoverlapping` here.
self.copy(self.head, old_head, head_len);
self.head = old_head;
}
}
}

/// Shortens the deque, keeping the first `len` elements and dropping
/// the rest.
///
Expand Down
49 changes: 49 additions & 0 deletions library/alloc/tests/vec_deque_alloc_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![feature(alloc_error_hook, allocator_api)]

use std::{
alloc::{set_alloc_error_hook, AllocError, Allocator, Layout, System},
collections::VecDeque,
panic::{catch_unwind, AssertUnwindSafe},
ptr::NonNull,
};

#[test]
fn test_shrink_to_unwind() {
// This tests that `shrink_to` leaves the deque in a consistent state when
// the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369
// but changed to hopefully not have any UB even if the test fails.

struct BadAlloc;

unsafe impl Allocator for BadAlloc {
fn allocate(&self, l: Layout) -> Result<NonNull<[u8]>, AllocError> {
// We allocate zeroed here so that the whole buffer of the deque
// is always initialized. That way, even if the deque is left in
// an inconsistent state, no uninitialized memory should be accessed.
System.allocate_zeroed(l)
}

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { System.deallocate(ptr, layout) }
}

unsafe fn shrink(
&self,
_ptr: NonNull<u8>,
_old_layout: Layout,
_new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
Err(AllocError)
}
}

set_alloc_error_hook(|_| panic!("alloc error"));

let mut v = VecDeque::with_capacity_in(15, BadAlloc);
v.push_back(1);
v.push_front(2);
// This should unwind because it calls `BadAlloc::shrink` and then `handle_alloc_error` which unwinds.
assert!(catch_unwind(AssertUnwindSafe(|| v.shrink_to_fit())).is_err());
// This should only pass if the deque is left in a consistent state.
assert_eq!(v, [2, 1]);
}
2 changes: 1 addition & 1 deletion library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ use crate::ptr::{self, NonNull};
mod lazy;
mod once;

#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub use lazy::LazyCell;
#[stable(feature = "once_cell", since = "1.70.0")]
pub use once::OnceCell;
Expand Down
20 changes: 7 additions & 13 deletions library/core/src/cell/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ enum State<T, F> {
/// # Examples
///
/// ```
/// #![feature(lazy_cell)]
///
/// use std::cell::LazyCell;
///
/// let lazy: LazyCell<i32> = LazyCell::new(|| {
Expand All @@ -36,7 +34,7 @@ enum State<T, F> {
/// // 92
/// // 92
/// ```
#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub struct LazyCell<T, F = fn() -> T> {
state: UnsafeCell<State<T, F>>,
}
Expand All @@ -47,8 +45,6 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// # Examples
///
/// ```
/// #![feature(lazy_cell)]
///
/// use std::cell::LazyCell;
///
/// let hello = "Hello, World!".to_string();
Expand All @@ -58,7 +54,8 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// ```
#[inline]
#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub const fn new(f: F) -> LazyCell<T, F> {
LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
}
Expand All @@ -70,7 +67,6 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// # Examples
///
/// ```
/// #![feature(lazy_cell)]
/// #![feature(lazy_cell_consume)]
///
/// use std::cell::LazyCell;
Expand Down Expand Up @@ -99,8 +95,6 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// # Examples
///
/// ```
/// #![feature(lazy_cell)]
///
/// use std::cell::LazyCell;
///
/// let lazy = LazyCell::new(|| 92);
Expand All @@ -109,7 +103,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// assert_eq!(&*lazy, &92);
/// ```
#[inline]
#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn force(this: &LazyCell<T, F>) -> &T {
// SAFETY:
// This invalidates any mutable references to the data. The resulting
Expand Down Expand Up @@ -173,7 +167,7 @@ impl<T, F> LazyCell<T, F> {
}
}

#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
type Target = T;
#[inline]
Expand All @@ -182,7 +176,7 @@ impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
}
}

#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: Default> Default for LazyCell<T> {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
Expand All @@ -191,7 +185,7 @@ impl<T: Default> Default for LazyCell<T> {
}
}

#[unstable(feature = "lazy_cell", issue = "109736")]
#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("LazyCell");
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ mod c_char_definition {
any(target_arch = "aarch64", target_arch = "riscv64")
),
all(target_os = "nto", target_arch = "aarch64"),
target_os = "horizon"
target_os = "horizon",
target_os = "aix",
))] {
pub type c_char = u8;
} else {
Expand Down
Loading

0 comments on commit 0a59f11

Please sign in to comment.