Auto merge of #77436 - JohnTitor:rollup-65dh7rp, r=JohnTitor
Rollup of 11 pull requests Successful merges: - #76851 (Fix 'FIXME' about using NonZeroU32 instead of u32.) - #76979 (Improve std::sys::windows::compat) - #77111 (Stabilize slice_ptr_range.) - #77147 (Split sys_common::Mutex in StaticMutex and MovableMutex.) - #77312 (Remove outdated line from `publish_toolstate` hook) - #77362 (Fix is_absolute on WASI) - #77375 (rustc_metadata: Do not forget to encode inherent impls for foreign types) - #77385 (Improve the example for ptr::copy) - #77389 (Fix some clippy lints) - #77399 (BTreeMap: use Unique::from to avoid a cast where type information exists) - #77429 (Link `new` method in `DefautHasher`s doc) Failed merges: r? `@ghost`
This commit is contained in:
commit
f283d3f02c
|
@ -1,6 +1,6 @@
|
|||
//! List of the accepted feature gates.
|
||||
|
||||
use super::{Feature, State};
|
||||
use super::{to_nonzero, Feature, State};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
macro_rules! declare_features {
|
||||
|
@ -14,7 +14,7 @@ macro_rules! declare_features {
|
|||
state: State::Accepted,
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: $issue,
|
||||
issue: to_nonzero($issue),
|
||||
edition: None,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! List of the active feature gates.
|
||||
|
||||
use super::{Feature, State};
|
||||
use super::{to_nonzero, Feature, State};
|
||||
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
@ -29,7 +29,7 @@ macro_rules! declare_features {
|
|||
state: State::Active { set: set!($feature) },
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: $issue,
|
||||
issue: to_nonzero($issue),
|
||||
edition: $edition,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
|
|
|
@ -46,17 +46,11 @@ pub struct Feature {
|
|||
pub state: State,
|
||||
pub name: Symbol,
|
||||
pub since: &'static str,
|
||||
issue: Option<u32>, // FIXME: once #58732 is done make this an Option<NonZeroU32>
|
||||
issue: Option<NonZeroU32>,
|
||||
pub edition: Option<Edition>,
|
||||
description: &'static str,
|
||||
}
|
||||
|
||||
impl Feature {
|
||||
fn issue(&self) -> Option<NonZeroU32> {
|
||||
self.issue.and_then(NonZeroU32::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stability {
|
||||
Unstable,
|
||||
|
@ -102,8 +96,8 @@ impl UnstableFeatures {
|
|||
fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
|
||||
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
|
||||
// FIXME (#28244): enforce that active features have issue numbers
|
||||
// assert!(info.issue().is_some())
|
||||
info.issue()
|
||||
// assert!(info.issue.is_some())
|
||||
info.issue
|
||||
} else {
|
||||
// search in Accepted, Removed, or Stable Removed features
|
||||
let found = ACCEPTED_FEATURES
|
||||
|
@ -112,12 +106,21 @@ fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
|
|||
.chain(STABLE_REMOVED_FEATURES)
|
||||
.find(|t| t.name == feature);
|
||||
match found {
|
||||
Some(found) => found.issue(),
|
||||
Some(found) => found.issue,
|
||||
None => panic!("feature `{}` is not declared anywhere", feature),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn to_nonzero(n: Option<u32>) -> Option<NonZeroU32> {
|
||||
// Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable
|
||||
// in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
|
||||
match n {
|
||||
None => None,
|
||||
Some(n) => NonZeroU32::new(n),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GateIssue {
|
||||
Language,
|
||||
Library(Option<NonZeroU32>),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! List of the removed feature gates.
|
||||
|
||||
use super::{Feature, State};
|
||||
use super::{to_nonzero, Feature, State};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
macro_rules! declare_features {
|
||||
|
@ -14,7 +14,7 @@ macro_rules! declare_features {
|
|||
state: State::Removed { reason: $reason },
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: $issue,
|
||||
issue: to_nonzero($issue),
|
||||
edition: None,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ macro_rules! declare_features {
|
|||
state: State::Stabilized { reason: None },
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: $issue,
|
||||
issue: to_nonzero($issue),
|
||||
edition: None,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
|
|
|
@ -1753,6 +1753,7 @@ impl EncodeContext<'a, 'tcx> {
|
|||
self.encode_const_stability(def_id);
|
||||
self.encode_deprecation(def_id);
|
||||
self.encode_item_type(def_id);
|
||||
self.encode_inherent_implementations(def_id);
|
||||
if let hir::ForeignItemKind::Fn(..) = nitem.kind {
|
||||
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
|
||||
self.encode_variances_of(def_id);
|
||||
|
|
|
@ -128,7 +128,7 @@ impl<K, V> BoxedNode<K, V> {
|
|||
}
|
||||
|
||||
fn from_internal(node: Box<InternalNode<K, V>>) -> Self {
|
||||
BoxedNode { ptr: Box::into_unique(node).cast() }
|
||||
BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) }
|
||||
}
|
||||
|
||||
unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
|
||||
|
|
|
@ -1901,11 +1901,21 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
|
|||
/// ```
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// /// # Safety:
|
||||
/// /// * `ptr` must be correctly aligned for its type and non-zero.
|
||||
/// /// * `ptr` must be valid for reads of `elts` contiguous objects of type `T`.
|
||||
/// /// * Those elements must not be used after calling this function unless `T: Copy`.
|
||||
/// # #[allow(dead_code)]
|
||||
/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
|
||||
/// let mut dst = Vec::with_capacity(elts);
|
||||
/// dst.set_len(elts);
|
||||
///
|
||||
/// // SAFETY: Our precondition ensures the source is aligned and valid,
|
||||
/// // and `Vec::with_capacity` ensures that we have usable space to write them.
|
||||
/// ptr::copy(ptr, dst.as_mut_ptr(), elts);
|
||||
///
|
||||
/// // SAFETY: We created it with this much capacity earlier,
|
||||
/// // and the previous `copy` has initialized these elements.
|
||||
/// dst.set_len(elts);
|
||||
/// dst
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -458,8 +458,6 @@ impl<T> [T] {
|
|||
/// element of this slice:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_ptr_range)]
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
/// let x = &a[1] as *const _;
|
||||
/// let y = &5 as *const _;
|
||||
|
@ -469,7 +467,7 @@ impl<T> [T] {
|
|||
/// ```
|
||||
///
|
||||
/// [`as_ptr`]: #method.as_ptr
|
||||
#[unstable(feature = "slice_ptr_range", issue = "65807")]
|
||||
#[stable(feature = "slice_ptr_range", since = "1.48.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub const fn as_ptr_range(&self) -> Range<*const T> {
|
||||
|
@ -511,7 +509,7 @@ impl<T> [T] {
|
|||
/// common in C++.
|
||||
///
|
||||
/// [`as_mut_ptr`]: #method.as_mut_ptr
|
||||
#[unstable(feature = "slice_ptr_range", issue = "65807")]
|
||||
#[stable(feature = "slice_ptr_range", since = "1.48.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
|
||||
|
|
|
@ -2836,11 +2836,10 @@ impl DefaultHasher {
|
|||
|
||||
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
|
||||
impl Default for DefaultHasher {
|
||||
// FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link
|
||||
// resolution failure when re-exporting libstd items. When #56922 fixed,
|
||||
// link `new` to [DefaultHasher::new] again.
|
||||
/// Creates a new `DefaultHasher` using `new`.
|
||||
/// Creates a new `DefaultHasher` using [`new`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`new`]: DefaultHasher::new
|
||||
fn default() -> DefaultHasher {
|
||||
DefaultHasher::new()
|
||||
}
|
||||
|
|
|
@ -1838,7 +1838,7 @@ impl Path {
|
|||
// FIXME: Allow Redox prefixes
|
||||
self.has_root() || has_redox_scheme(self.as_u8_slice())
|
||||
} else {
|
||||
self.has_root() && (cfg!(unix) || self.prefix().is_some())
|
||||
self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -553,8 +553,8 @@ impl Condvar {
|
|||
unsafe { self.inner.notify_all() }
|
||||
}
|
||||
|
||||
fn verify(&self, mutex: &sys_mutex::Mutex) {
|
||||
let addr = mutex as *const _ as usize;
|
||||
fn verify(&self, mutex: &sys_mutex::MovableMutex) {
|
||||
let addr = mutex.raw() as *const _ as usize;
|
||||
match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
|
||||
// If we got out 0, then we have successfully bound the mutex to
|
||||
// this cvar.
|
||||
|
|
|
@ -166,12 +166,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
|
||||
pub struct Mutex<T: ?Sized> {
|
||||
// Note that this mutex is in a *box*, not inlined into the struct itself.
|
||||
// Once a native mutex has been used once, its address can never change (it
|
||||
// can't be moved). This mutex type can be safely moved at any time, so to
|
||||
// ensure that the native mutex is used correctly we box the inner mutex to
|
||||
// give it a constant address.
|
||||
inner: Box<sys::Mutex>,
|
||||
inner: sys::MovableMutex,
|
||||
poison: poison::Flag,
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
@ -218,15 +213,11 @@ impl<T> Mutex<T> {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new(t: T) -> Mutex<T> {
|
||||
let mut m = Mutex {
|
||||
inner: box sys::Mutex::new(),
|
||||
Mutex {
|
||||
inner: sys::MovableMutex::new(),
|
||||
poison: poison::Flag::new(),
|
||||
data: UnsafeCell::new(t),
|
||||
};
|
||||
unsafe {
|
||||
m.inner.init();
|
||||
}
|
||||
m
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +369,6 @@ impl<T: ?Sized> Mutex<T> {
|
|||
(ptr::read(inner), ptr::read(poison), ptr::read(data))
|
||||
};
|
||||
mem::forget(self);
|
||||
inner.destroy(); // Keep in sync with the `Drop` impl.
|
||||
drop(inner);
|
||||
|
||||
poison::map_result(poison.borrow(), |_| data.into_inner())
|
||||
|
@ -411,18 +401,6 @@ impl<T: ?Sized> Mutex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
|
||||
fn drop(&mut self) {
|
||||
// This is actually safe b/c we know that there is no further usage of
|
||||
// this mutex (it's up to the user to arrange for a mutex to get
|
||||
// dropped, that's not our job)
|
||||
//
|
||||
// IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
|
||||
unsafe { self.inner.destroy() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mutex_from", since = "1.24.0")]
|
||||
impl<T> From<T> for Mutex<T> {
|
||||
/// Creates a new mutex in an unlocked state ready for use.
|
||||
|
@ -509,7 +487,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
|
||||
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex {
|
||||
&guard.lock.inner
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ mod imp {
|
|||
use crate::ptr;
|
||||
use crate::sys_common::os_str_bytes::*;
|
||||
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
static mut ARGC: isize = 0;
|
||||
static mut ARGV: *const *const u8 = ptr::null();
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
let _guard = LOCK.lock();
|
||||
|
|
|
@ -80,13 +80,13 @@ mod imp {
|
|||
use crate::ptr;
|
||||
use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
|
||||
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
static ARGC: AtomicIsize = AtomicIsize::new(0);
|
||||
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
|
||||
// We never call `ENV_LOCK.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
|
||||
unsafe fn really_init(argc: isize, argv: *const *const u8) {
|
||||
let _guard = LOCK.lock();
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::slice;
|
|||
use crate::str;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys::fd;
|
||||
use crate::sys_common::mutex::{Mutex, MutexGuard};
|
||||
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
|
||||
use crate::vec;
|
||||
|
||||
use libc::{c_char, c_int, c_void};
|
||||
|
@ -470,10 +470,9 @@ pub unsafe fn environ() -> *mut *const *const c_char {
|
|||
&mut environ
|
||||
}
|
||||
|
||||
pub unsafe fn env_lock() -> MutexGuard<'static> {
|
||||
// We never call `ENV_LOCK.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static ENV_LOCK: Mutex = Mutex::new();
|
||||
pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static ENV_LOCK: StaticMutex = StaticMutex::new();
|
||||
ENV_LOCK.lock()
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ mod imp {
|
|||
use crate::marker::PhantomData;
|
||||
use crate::ptr;
|
||||
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
static mut ARGC: isize = 0;
|
||||
static mut ARGV: *const *const u8 = ptr::null();
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
let _guard = LOCK.lock();
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::path::{self, Path, PathBuf};
|
|||
use crate::slice;
|
||||
use crate::str;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::mutex::{Mutex, MutexGuard};
|
||||
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
|
||||
use libc::{self, c_char /*,c_void */, c_int};
|
||||
/*use sys::fd; this one is probably important */
|
||||
use crate::vec;
|
||||
|
@ -212,10 +212,9 @@ pub unsafe fn environ() -> *mut *const *const c_char {
|
|||
&mut environ
|
||||
}
|
||||
|
||||
pub unsafe fn env_lock() -> MutexGuard<'static> {
|
||||
// We never call `ENV_LOCK.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static ENV_LOCK: Mutex = Mutex::new();
|
||||
pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static ENV_LOCK: StaticMutex = StaticMutex::new();
|
||||
ENV_LOCK.lock()
|
||||
}
|
||||
|
||||
|
|
|
@ -1032,7 +1032,7 @@ extern "system" {
|
|||
// Functions that aren't available on every version of Windows that we support,
|
||||
// but we still use them and just provide some form of a fallback implementation.
|
||||
compat_fn! {
|
||||
kernel32:
|
||||
"kernel32":
|
||||
|
||||
pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
|
||||
_lpTargetFileName: LPCWSTR,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
//! function is available but afterwards it's just a load and a jump.
|
||||
|
||||
use crate::ffi::CString;
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::sys::c;
|
||||
|
||||
pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
|
||||
|
@ -28,45 +27,69 @@ pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize {
|
||||
let value = lookup(module, symbol).unwrap_or(fallback);
|
||||
ptr.store(value, Ordering::SeqCst);
|
||||
value
|
||||
}
|
||||
|
||||
macro_rules! compat_fn {
|
||||
($module:ident: $(
|
||||
($module:literal: $(
|
||||
$(#[$meta:meta])*
|
||||
pub fn $symbol:ident($($argname:ident: $argtype:ty),*)
|
||||
-> $rettype:ty {
|
||||
$($body:expr);*
|
||||
}
|
||||
pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block
|
||||
)*) => ($(
|
||||
#[allow(unused_variables)]
|
||||
$(#[$meta])*
|
||||
pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
|
||||
pub mod $symbol {
|
||||
use super::*;
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::mem;
|
||||
|
||||
type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
|
||||
|
||||
static PTR: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[allow(unused_variables)]
|
||||
unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body
|
||||
|
||||
/// This address is stored in `PTR` to incidate an unavailable API.
|
||||
///
|
||||
/// This way, call() will end up calling fallback() if it is unavailable.
|
||||
///
|
||||
/// This is a `static` to avoid rustc duplicating `fn fallback()`
|
||||
/// into both load() and is_available(), which would break
|
||||
/// is_available()'s comparison. By using the same static variable
|
||||
/// in both places, they'll refer to the same (copy of the)
|
||||
/// function.
|
||||
///
|
||||
/// LLVM merging the address of fallback with other functions
|
||||
/// (because of unnamed_addr) is fine, since it's only compared to
|
||||
/// an address from GetProcAddress from an external dll.
|
||||
static FALLBACK: F = fallback;
|
||||
|
||||
#[cold]
|
||||
fn load() -> usize {
|
||||
crate::sys::compat::store_func(&PTR,
|
||||
stringify!($module),
|
||||
stringify!($symbol),
|
||||
fallback as usize)
|
||||
}
|
||||
unsafe extern "system" fn fallback($($argname: $argtype),*)
|
||||
-> $rettype {
|
||||
$($body);*
|
||||
// There is no locking here. It's okay if this is executed by multiple threads in
|
||||
// parallel. `lookup` will result in the same value, and it's okay if they overwrite
|
||||
// eachothers result as long as they do so atomically. We don't need any guarantees
|
||||
// about memory ordering, as this involves just a single atomic variable which is
|
||||
// not used to protect or order anything else.
|
||||
let addr = crate::sys::compat::lookup($module, stringify!($symbol))
|
||||
.unwrap_or(FALLBACK as usize);
|
||||
PTR.store(addr, Ordering::Relaxed);
|
||||
addr
|
||||
}
|
||||
|
||||
let addr = match PTR.load(Ordering::SeqCst) {
|
||||
0 => load(),
|
||||
n => n,
|
||||
};
|
||||
mem::transmute::<usize, F>(addr)($($argname),*)
|
||||
fn addr() -> usize {
|
||||
match PTR.load(Ordering::Relaxed) {
|
||||
0 => load(),
|
||||
addr => addr,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn is_available() -> bool {
|
||||
addr() != FALLBACK as usize
|
||||
}
|
||||
|
||||
pub unsafe fn call($($argname: $argtype),*) -> $rettype {
|
||||
mem::transmute::<usize, F>(addr())($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
pub use $symbol::call as $symbol;
|
||||
)*)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ use crate::cell::{Cell, UnsafeCell};
|
|||
use crate::mem::{self, MaybeUninit};
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::sys::c;
|
||||
use crate::sys::compat;
|
||||
|
||||
pub struct Mutex {
|
||||
// This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
|
||||
|
@ -40,8 +39,8 @@ struct Inner {
|
|||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Kind {
|
||||
SRWLock = 1,
|
||||
CriticalSection = 2,
|
||||
SRWLock,
|
||||
CriticalSection,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -130,21 +129,7 @@ impl Mutex {
|
|||
}
|
||||
|
||||
fn kind() -> Kind {
|
||||
static KIND: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
let val = KIND.load(Ordering::SeqCst);
|
||||
if val == Kind::SRWLock as usize {
|
||||
return Kind::SRWLock;
|
||||
} else if val == Kind::CriticalSection as usize {
|
||||
return Kind::CriticalSection;
|
||||
}
|
||||
|
||||
let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
|
||||
None => Kind::CriticalSection,
|
||||
Some(..) => Kind::SRWLock,
|
||||
};
|
||||
KIND.store(ret as usize, Ordering::SeqCst);
|
||||
ret
|
||||
if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection }
|
||||
}
|
||||
|
||||
pub struct ReentrantMutex {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::mem;
|
||||
use crate::ptr;
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
type Queue = Vec<Box<dyn FnOnce()>>;
|
||||
|
||||
|
@ -12,9 +12,8 @@ type Queue = Vec<Box<dyn FnOnce()>>;
|
|||
// on poisoning and this module needs to operate at a lower level than requiring
|
||||
// the thread infrastructure to be in place (useful on the borders of
|
||||
// initialization/destruction).
|
||||
// We never call `LOCK.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
static mut QUEUE: *mut Queue = ptr::null_mut();
|
||||
|
||||
const DONE: *mut Queue = 1_usize as *mut _;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::sys::condvar as imp;
|
||||
use crate::sys_common::mutex::{self, Mutex};
|
||||
use crate::sys_common::mutex::MovableMutex;
|
||||
use crate::time::Duration;
|
||||
|
||||
/// An OS-based condition variable.
|
||||
|
@ -46,8 +46,8 @@ impl Condvar {
|
|||
/// Behavior is also undefined if more than one mutex is used concurrently
|
||||
/// on this condition variable.
|
||||
#[inline]
|
||||
pub unsafe fn wait(&self, mutex: &Mutex) {
|
||||
self.0.wait(mutex::raw(mutex))
|
||||
pub unsafe fn wait(&self, mutex: &MovableMutex) {
|
||||
self.0.wait(mutex.raw())
|
||||
}
|
||||
|
||||
/// Waits for a signal on the specified mutex with a timeout duration
|
||||
|
@ -57,8 +57,8 @@ impl Condvar {
|
|||
/// Behavior is also undefined if more than one mutex is used concurrently
|
||||
/// on this condition variable.
|
||||
#[inline]
|
||||
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
|
||||
self.0.wait_timeout(mutex::raw(mutex), dur)
|
||||
pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
|
||||
self.0.wait_timeout(mutex.raw(), dur)
|
||||
}
|
||||
|
||||
/// Deallocates all resources associated with this condition variable.
|
||||
|
|
|
@ -1,97 +1,47 @@
|
|||
use crate::sys::mutex as imp;
|
||||
|
||||
/// An OS-based mutual exclusion lock.
|
||||
/// An OS-based mutual exclusion lock, meant for use in static variables.
|
||||
///
|
||||
/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
|
||||
/// this mutex is unsafe and it is recommended to instead use the safe wrapper
|
||||
/// at the top level of the crate instead of this type.
|
||||
pub struct Mutex(imp::Mutex);
|
||||
/// This mutex has a const constructor ([`StaticMutex::new`]), does not
|
||||
/// implement `Drop` to cleanup resources, and causes UB when moved or used
|
||||
/// reentrantly.
|
||||
///
|
||||
/// This mutex does not implement poisoning.
|
||||
///
|
||||
/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
|
||||
/// `destroy()`.
|
||||
pub struct StaticMutex(imp::Mutex);
|
||||
|
||||
unsafe impl Sync for Mutex {}
|
||||
unsafe impl Sync for StaticMutex {}
|
||||
|
||||
impl Mutex {
|
||||
impl StaticMutex {
|
||||
/// Creates a new mutex for use.
|
||||
///
|
||||
/// Behavior is undefined if the mutex is moved after it is
|
||||
/// first used with any of the functions below.
|
||||
/// Also, until `init` is called, behavior is undefined if this
|
||||
/// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
|
||||
/// are called by the thread currently holding the lock.
|
||||
/// Also, the behavior is undefined if this mutex is ever used reentrantly,
|
||||
/// i.e., `lock` is called by the thread currently holding the lock.
|
||||
#[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
|
||||
pub const fn new() -> Mutex {
|
||||
Mutex(imp::Mutex::new())
|
||||
}
|
||||
|
||||
/// Prepare the mutex for use.
|
||||
///
|
||||
/// This should be called once the mutex is at a stable memory address.
|
||||
/// If called, this must be the very first thing that happens to the mutex.
|
||||
/// Calling it in parallel with or after any operation (including another
|
||||
/// `init()`) is undefined behavior.
|
||||
#[inline]
|
||||
pub unsafe fn init(&mut self) {
|
||||
self.0.init()
|
||||
}
|
||||
|
||||
/// Locks the mutex blocking the current thread until it is available.
|
||||
///
|
||||
/// Behavior is undefined if the mutex has been moved between this and any
|
||||
/// previous function call.
|
||||
#[inline]
|
||||
pub unsafe fn raw_lock(&self) {
|
||||
self.0.lock()
|
||||
pub const fn new() -> Self {
|
||||
Self(imp::Mutex::new())
|
||||
}
|
||||
|
||||
/// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
|
||||
/// will be unlocked.
|
||||
#[inline]
|
||||
pub unsafe fn lock(&self) -> MutexGuard<'_> {
|
||||
self.raw_lock();
|
||||
MutexGuard(&self.0)
|
||||
}
|
||||
|
||||
/// Attempts to lock the mutex without blocking, returning whether it was
|
||||
/// successfully acquired or not.
|
||||
///
|
||||
/// Behavior is undefined if the mutex has been moved between this and any
|
||||
/// previous function call.
|
||||
/// It is undefined behaviour to call this function while locked, or if the
|
||||
/// mutex has been moved since the last time this was called.
|
||||
#[inline]
|
||||
pub unsafe fn try_lock(&self) -> bool {
|
||||
self.0.try_lock()
|
||||
pub unsafe fn lock(&self) -> StaticMutexGuard<'_> {
|
||||
self.0.lock();
|
||||
StaticMutexGuard(&self.0)
|
||||
}
|
||||
|
||||
/// Unlocks the mutex.
|
||||
///
|
||||
/// Behavior is undefined if the current thread does not actually hold the
|
||||
/// mutex.
|
||||
///
|
||||
/// Consider switching from the pair of raw_lock() and raw_unlock() to
|
||||
/// lock() whenever possible.
|
||||
#[inline]
|
||||
pub unsafe fn raw_unlock(&self) {
|
||||
self.0.unlock()
|
||||
}
|
||||
|
||||
/// Deallocates all resources associated with this mutex.
|
||||
///
|
||||
/// Behavior is undefined if there are current or will be future users of
|
||||
/// this mutex.
|
||||
#[inline]
|
||||
pub unsafe fn destroy(&self) {
|
||||
self.0.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// not meant to be exported to the outside world, just the containing module
|
||||
pub fn raw(mutex: &Mutex) -> &imp::Mutex {
|
||||
&mutex.0
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// A simple RAII utility for the above Mutex without the poisoning semantics.
|
||||
pub struct MutexGuard<'a>(&'a imp::Mutex);
|
||||
pub struct StaticMutexGuard<'a>(&'a imp::Mutex);
|
||||
|
||||
impl Drop for MutexGuard<'_> {
|
||||
impl Drop for StaticMutexGuard<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -99,3 +49,58 @@ impl Drop for MutexGuard<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An OS-based mutual exclusion lock.
|
||||
///
|
||||
/// This mutex does *not* have a const constructor, cleans up its resources in
|
||||
/// its `Drop` implementation, may safely be moved (when not borrowed), and
|
||||
/// does not cause UB when used reentrantly.
|
||||
///
|
||||
/// This mutex does not implement poisoning.
|
||||
///
|
||||
/// This is a wrapper around `Box<imp::Mutex>`, to allow the object to be moved
|
||||
/// without moving the raw mutex.
|
||||
pub struct MovableMutex(Box<imp::Mutex>);
|
||||
|
||||
unsafe impl Sync for MovableMutex {}
|
||||
|
||||
impl MovableMutex {
|
||||
/// Creates a new mutex.
|
||||
pub fn new() -> Self {
|
||||
let mut mutex = box imp::Mutex::new();
|
||||
unsafe { mutex.init() };
|
||||
Self(mutex)
|
||||
}
|
||||
|
||||
pub(crate) fn raw(&self) -> &imp::Mutex {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Locks the mutex blocking the current thread until it is available.
|
||||
#[inline]
|
||||
pub fn raw_lock(&self) {
|
||||
unsafe { self.0.lock() }
|
||||
}
|
||||
|
||||
/// Attempts to lock the mutex without blocking, returning whether it was
|
||||
/// successfully acquired or not.
|
||||
#[inline]
|
||||
pub fn try_lock(&self) -> bool {
|
||||
unsafe { self.0.try_lock() }
|
||||
}
|
||||
|
||||
/// Unlocks the mutex.
|
||||
///
|
||||
/// Behavior is undefined if the current thread does not actually hold the
|
||||
/// mutex.
|
||||
#[inline]
|
||||
pub unsafe fn raw_unlock(&self) {
|
||||
self.0.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MovableMutex {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.0.destroy() };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ mod tests;
|
|||
|
||||
use crate::sync::atomic::{self, AtomicUsize, Ordering};
|
||||
use crate::sys::thread_local_key as imp;
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
/// A type for TLS keys that are statically allocated.
|
||||
///
|
||||
|
@ -157,7 +157,7 @@ impl StaticKey {
|
|||
if imp::requires_synchronized_create() {
|
||||
// We never call `INIT_LOCK.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static INIT_LOCK: Mutex = Mutex::new();
|
||||
static INIT_LOCK: StaticMutex = StaticMutex::new();
|
||||
let _guard = INIT_LOCK.lock();
|
||||
let mut key = self.key.load(Ordering::SeqCst);
|
||||
if key == 0 {
|
||||
|
|
|
@ -972,9 +972,8 @@ pub struct ThreadId(NonZeroU64);
|
|||
impl ThreadId {
|
||||
// Generate a new unique thread ID.
|
||||
fn new() -> ThreadId {
|
||||
// We never call `GUARD.init()`, so it is UB to attempt to
|
||||
// acquire this mutex reentrantly!
|
||||
static GUARD: mutex::Mutex = mutex::Mutex::new();
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
|
||||
static mut COUNTER: u64 = 1;
|
||||
|
||||
unsafe {
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::error::Error;
|
|||
use crate::fmt;
|
||||
use crate::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use crate::sys::time;
|
||||
use crate::sys_common::mutex::Mutex;
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
use crate::sys_common::FromInner;
|
||||
|
||||
#[stable(feature = "time", since = "1.3.0")]
|
||||
|
@ -243,7 +243,7 @@ impl Instant {
|
|||
return Instant(os_now);
|
||||
}
|
||||
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
static LOCK: StaticMutex = StaticMutex::new();
|
||||
static mut LAST_NOW: time::Instant = time::Instant::zero();
|
||||
unsafe {
|
||||
let _lock = LOCK.lock();
|
||||
|
|
|
@ -159,7 +159,7 @@ where
|
|||
return summ5;
|
||||
}
|
||||
|
||||
total_run = total_run + loop_run;
|
||||
total_run += loop_run;
|
||||
// Longest we ever run for is 3s.
|
||||
if total_run > Duration::from_secs(3) {
|
||||
return summ5;
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<T: Write> PrettyFormatter<T> {
|
|||
stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
|
||||
let output = String::from_utf8_lossy(stdout);
|
||||
stdouts.push_str(&output);
|
||||
stdouts.push_str("\n");
|
||||
stdouts.push('\n');
|
||||
}
|
||||
}
|
||||
if !stdouts.is_empty() {
|
||||
|
|
|
@ -114,7 +114,7 @@ impl<T: Write> TerseFormatter<T> {
|
|||
stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
|
||||
let output = String::from_utf8_lossy(stdout);
|
||||
stdouts.push_str(&output);
|
||||
stdouts.push_str("\n");
|
||||
stdouts.push('\n');
|
||||
}
|
||||
}
|
||||
if !stdouts.is_empty() {
|
||||
|
@ -140,7 +140,7 @@ impl<T: Write> TerseFormatter<T> {
|
|||
fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
|
||||
let output = String::from_utf8_lossy(stdout);
|
||||
fail_out.push_str(&output);
|
||||
fail_out.push_str("\n");
|
||||
fail_out.push('\n');
|
||||
}
|
||||
}
|
||||
if !fail_out.is_empty() {
|
||||
|
|
|
@ -237,11 +237,9 @@ where
|
|||
let event = TestEvent::TeFiltered(filtered_descs);
|
||||
notify_about_test_event(event)?;
|
||||
|
||||
let (filtered_tests, filtered_benchs): (Vec<_>, _) =
|
||||
filtered_tests.into_iter().partition(|e| match e.testfn {
|
||||
StaticTestFn(_) | DynTestFn(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
|
||||
.into_iter()
|
||||
.partition(|e| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_)));
|
||||
|
||||
let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ impl Stats for [f64] {
|
|||
let mut v: f64 = 0.0;
|
||||
for s in self {
|
||||
let x = *s - mean;
|
||||
v = v + x * x;
|
||||
v += x * x;
|
||||
}
|
||||
// N.B., this is _supposed to be_ len-1, not len. If you
|
||||
// change it back to len, you will be calculating a
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#![feature(extern_types)]
|
||||
|
||||
extern "C" {
|
||||
pub type CrossCrate;
|
||||
}
|
||||
|
||||
impl CrossCrate {
|
||||
pub fn foo(&self) {}
|
||||
}
|
|
@ -1,19 +1,26 @@
|
|||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
// Test that inherent impls can be defined for extern types.
|
||||
|
||||
// check-pass
|
||||
// aux-build:extern-types-inherent-impl.rs
|
||||
|
||||
#![feature(extern_types)]
|
||||
|
||||
extern {
|
||||
type A;
|
||||
extern crate extern_types_inherent_impl;
|
||||
use extern_types_inherent_impl::CrossCrate;
|
||||
|
||||
extern "C" {
|
||||
type Local;
|
||||
}
|
||||
|
||||
impl A {
|
||||
fn foo(&self) { }
|
||||
impl Local {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn use_foo(x: &A) {
|
||||
fn use_foo(x: &Local, y: &CrossCrate) {
|
||||
Local::foo(x);
|
||||
x.foo();
|
||||
CrossCrate::foo(y);
|
||||
y.foo();
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
fn main() {}
|
||||
|
|
|
@ -7,7 +7,6 @@ struct Test {
|
|||
fn main() {}
|
||||
|
||||
fn testing(test: Test) {
|
||||
let _ = test.comps.inner.lock().unwrap();
|
||||
let _ = test.comps.inner.try_lock();
|
||||
//~^ ERROR: field `inner` of struct `Mutex` is private
|
||||
//~| ERROR: no method named `unwrap` found
|
||||
}
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
error[E0616]: field `inner` of struct `Mutex` is private
|
||||
--> $DIR/issue-54062.rs:10:24
|
||||
|
|
||||
LL | let _ = test.comps.inner.lock().unwrap();
|
||||
LL | let _ = test.comps.inner.try_lock();
|
||||
| ^^^^^ private field
|
||||
|
||||
error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope
|
||||
--> $DIR/issue-54062.rs:10:37
|
||||
|
|
||||
LL | let _ = test.comps.inner.lock().unwrap();
|
||||
| ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>`
|
||||
error: aborting due to previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0599, E0616.
|
||||
For more information about an error, try `rustc --explain E0599`.
|
||||
For more information about this error, try `rustc --explain E0616`.
|
||||
|
|
|
@ -157,9 +157,6 @@ def issue(
|
|||
|
||||
cc @{}, do you think you would have time to do the follow-up work?
|
||||
If so, that would be great!
|
||||
|
||||
And nominating for compiler team prioritization.
|
||||
|
||||
''').format(
|
||||
relevant_pr_number, tool, status_description,
|
||||
REPOS.get(tool), relevant_pr_user
|
||||
|
|
Loading…
Reference in New Issue