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:
bors 2020-10-02 00:48:41 +00:00
commit f283d3f02c
36 changed files with 241 additions and 240 deletions

View File

@ -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,)*),
}

View File

@ -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,)*),
}

View File

@ -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>),

View File

@ -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,)*),
}

View File

@ -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);

View File

@ -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 {

View File

@ -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
/// }
/// ```

View File

@ -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> {

View File

@ -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()
}

View File

@ -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())
}
}

View File

@ -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.

View File

@ -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
}

View File

@ -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();

View File

@ -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();

View File

@ -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()
}

View File

@ -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();

View File

@ -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()
}

View File

@ -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,

View File

@ -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;
)*)
}

View File

@ -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 {

View File

@ -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 _;

View File

@ -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.

View File

@ -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() };
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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();

View File

@ -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;

View File

@ -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() {

View File

@ -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() {

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1,9 @@
#![feature(extern_types)]
extern "C" {
pub type CrossCrate;
}
impl CrossCrate {
pub fn foo(&self) {}
}

View File

@ -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() {}

View File

@ -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
}

View File

@ -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`.

View File

@ -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