mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 12:36:47 +00:00
Auto merge of #121904 - matthiaskrgr:rollup-qcq0d3h, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #121666 (Use the OS thread name by default if `THREAD_INFO` has not been initialized) - #121758 (Move thread local implementation to `sys`) - #121759 (attempt to further clarify addr_of docs) - #121855 (Correctly generate item info of trait items) - #121888 (style library/core/src/error.rs) - #121892 (The ordinary lowering of `thir::ExprKind::Let` is unreachable) - #121895 (avoid collecting into vecs in some places) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5119208fd7
@ -357,31 +357,27 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
|
||||
|
||||
let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
|
||||
|
||||
let eligible_def_ids: Vec<DefId> = tcx
|
||||
.mir_keys(())
|
||||
.iter()
|
||||
.filter_map(|local_def_id| {
|
||||
let def_id = local_def_id.to_def_id();
|
||||
let kind = tcx.def_kind(def_id);
|
||||
// `mir_keys` will give us `DefId`s for all kinds of things, not
|
||||
// just "functions", like consts, statics, etc. Filter those out.
|
||||
// If `ignore_unused_generics` was specified, filter out any
|
||||
// generic functions from consideration as well.
|
||||
if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) {
|
||||
return None;
|
||||
}
|
||||
if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
|
||||
return None;
|
||||
}
|
||||
Some(local_def_id.to_def_id())
|
||||
})
|
||||
.collect();
|
||||
let eligible_def_ids = tcx.mir_keys(()).iter().filter_map(|local_def_id| {
|
||||
let def_id = local_def_id.to_def_id();
|
||||
let kind = tcx.def_kind(def_id);
|
||||
// `mir_keys` will give us `DefId`s for all kinds of things, not
|
||||
// just "functions", like consts, statics, etc. Filter those out.
|
||||
// If `ignore_unused_generics` was specified, filter out any
|
||||
// generic functions from consideration as well.
|
||||
if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) {
|
||||
return None;
|
||||
}
|
||||
if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
|
||||
return None;
|
||||
}
|
||||
Some(local_def_id.to_def_id())
|
||||
});
|
||||
|
||||
let codegenned_def_ids = codegenned_and_inlined_items(tcx);
|
||||
|
||||
// For each `DefId` that should have coverage instrumentation but wasn't
|
||||
// codegenned, add it to the function coverage map as an unused function.
|
||||
for def_id in eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) {
|
||||
for def_id in eligible_def_ids.filter(|id| !codegenned_def_ids.contains(id)) {
|
||||
// Skip any function that didn't have coverage data added to it by the
|
||||
// coverage instrumentor.
|
||||
let body = tcx.instance_mir(ty::InstanceDef::Item(def_id));
|
||||
|
@ -860,10 +860,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
traits with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits
|
||||
.iter()
|
||||
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
|
||||
.collect::<Vec<_>>(),
|
||||
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
|
@ -2156,10 +2156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err.span_suggestions(
|
||||
span.shrink_to_hi().with_hi(expr_span.hi()),
|
||||
"you might have meant to use an associated function to build this type",
|
||||
items
|
||||
.iter()
|
||||
.map(|(_, name, args)| suggestion(name, *args))
|
||||
.collect::<Vec<String>>(),
|
||||
items.iter().map(|(_, name, args)| suggestion(name, *args)),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
@ -109,38 +109,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.cfg.goto(else_blk, source_info, join_block);
|
||||
join_block.unit()
|
||||
}
|
||||
ExprKind::Let { expr, ref pat } => {
|
||||
let scope = this.local_scope();
|
||||
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
|
||||
this.lower_let_expr(block, expr, pat, scope, None, expr_span, true)
|
||||
});
|
||||
|
||||
this.cfg.push_assign_constant(
|
||||
true_block,
|
||||
source_info,
|
||||
destination,
|
||||
ConstOperand {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
const_: Const::from_bool(this.tcx, true),
|
||||
},
|
||||
);
|
||||
|
||||
this.cfg.push_assign_constant(
|
||||
false_block,
|
||||
source_info,
|
||||
destination,
|
||||
ConstOperand {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
const_: Const::from_bool(this.tcx, false),
|
||||
},
|
||||
);
|
||||
|
||||
let join_block = this.cfg.start_new_block();
|
||||
this.cfg.goto(true_block, source_info, join_block);
|
||||
this.cfg.goto(false_block, source_info, join_block);
|
||||
join_block.unit()
|
||||
ExprKind::Let { .. } => {
|
||||
// After desugaring, `let` expressions should only appear inside `if`
|
||||
// expressions or `match` guards, possibly nested within a let-chain.
|
||||
// In both cases they are specifically handled by the lowerings of
|
||||
// those expressions, so this case is currently unreachable.
|
||||
span_bug!(expr_span, "unexpected let expression outside of if or match-guard");
|
||||
}
|
||||
ExprKind::NeverToAny { source } => {
|
||||
let source_expr = &this.thir[source];
|
||||
|
@ -1884,10 +1884,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
err.span_suggestions_with_style(
|
||||
path_span.shrink_to_hi().with_hi(call_span.hi()),
|
||||
"you might have meant to use an associated function to build this type",
|
||||
items
|
||||
.iter()
|
||||
.map(|(_, name, len)| suggestion(name, *len))
|
||||
.collect::<Vec<String>>(),
|
||||
items.iter().map(|(_, name, len)| suggestion(name, *len)),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
|
@ -57,7 +57,7 @@ impl<'tcx> ObligationStorage<'tcx> {
|
||||
|
||||
fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> {
|
||||
let mut obligations = mem::take(&mut self.pending);
|
||||
obligations.extend(self.overflowed.drain(..));
|
||||
obligations.append(&mut self.overflowed);
|
||||
obligations
|
||||
}
|
||||
|
||||
|
@ -183,6 +183,7 @@ pub trait Error: Debug + Display {
|
||||
#[allow(unused_variables)]
|
||||
fn provide<'a>(&'a self, request: &mut Request<'a>) {}
|
||||
}
|
||||
|
||||
mod private {
|
||||
// This is a hack to prevent `type_id` from being overridden by `Error`
|
||||
// implementations, since that can enable unsound downcasting.
|
||||
|
@ -2071,11 +2071,16 @@ impl<F: FnPtr> fmt::Debug for F {
|
||||
/// as all other references. This macro can create a raw pointer *without* creating
|
||||
/// a reference first.
|
||||
///
|
||||
/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads
|
||||
/// from the place or requires the place to be dereferenceable. This means that
|
||||
/// `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
|
||||
/// Note however that `addr_of!((*ptr).field)` still requires the projection to
|
||||
/// `field` to be in-bounds, using the same rules as [`offset`].
|
||||
/// See [`addr_of_mut`] for how to create a pointer to uninitialized data.
|
||||
/// Doing that with `addr_of` would not make much sense since one could only
|
||||
/// read the data, and that would be Undefined Behavior.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `expr` in `addr_of!(expr)` is evaluated as a place expression, but never loads from the
|
||||
/// place or requires the place to be dereferenceable. This means that `addr_of!((*ptr).field)`
|
||||
/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`].
|
||||
/// However, `addr_of!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
|
||||
///
|
||||
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
|
||||
/// `addr_of!` like everywhere else, in which case a reference is created to call `Deref::deref` or
|
||||
@ -2086,6 +2091,8 @@ impl<F: FnPtr> fmt::Debug for F {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// **Correct usage: Creating a pointer to unaligned data**
|
||||
///
|
||||
/// ```
|
||||
/// use std::ptr;
|
||||
///
|
||||
@ -2101,9 +2108,27 @@ impl<F: FnPtr> fmt::Debug for F {
|
||||
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
|
||||
/// ```
|
||||
///
|
||||
/// See [`addr_of_mut`] for how to create a pointer to uninitialized data.
|
||||
/// Doing that with `addr_of` would not make much sense since one could only
|
||||
/// read the data, and that would be Undefined Behavior.
|
||||
/// **Incorrect usage: Out-of-bounds fields projection**
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(C)]
|
||||
/// struct MyStruct {
|
||||
/// field1: i32,
|
||||
/// field2: i32,
|
||||
/// }
|
||||
///
|
||||
/// let ptr: *const MyStruct = ptr::null();
|
||||
/// let fieldptr = unsafe { ptr::addr_of!((*ptr).field2) }; // Undefined Behavior ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// The field projection `.field2` would offset the pointer by 4 bytes,
|
||||
/// but the pointer is not in-bounds of an allocation for 4 bytes,
|
||||
/// so this offset is Undefined Behavior.
|
||||
/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the
|
||||
/// same requirements apply to field projections, even inside `addr_of!`. (In particular, it makes
|
||||
/// no difference whether the pointer is null or dangling.)
|
||||
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
@ -2120,11 +2145,12 @@ pub macro addr_of($place:expr) {
|
||||
/// as all other references. This macro can create a raw pointer *without* creating
|
||||
/// a reference first.
|
||||
///
|
||||
/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads
|
||||
/// from the place or requires the place to be dereferenceable. This means that
|
||||
/// `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
|
||||
/// Note however that `addr_of_mut!((*ptr).field)` still requires the projection to
|
||||
/// `field` to be in-bounds, using the same rules as [`offset`].
|
||||
/// # Safety
|
||||
///
|
||||
/// The `expr` in `addr_of_mut!(expr)` is evaluated as a place expression, but never loads from the
|
||||
/// place or requires the place to be dereferenceable. This means that `addr_of_mut!((*ptr).field)`
|
||||
/// still requires the projection to `field` to be in-bounds, using the same rules as [`offset`].
|
||||
/// However, `addr_of_mut!(*ptr)` is defined behavior even if `ptr` is null, dangling, or misaligned.
|
||||
///
|
||||
/// Note that `Deref`/`Index` coercions (and their mutable counterparts) are applied inside
|
||||
/// `addr_of_mut!` like everywhere else, in which case a reference is created to call `Deref::deref`
|
||||
@ -2135,7 +2161,7 @@ pub macro addr_of($place:expr) {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// **Creating a pointer to unaligned data:**
|
||||
/// **Correct usage: Creating a pointer to unaligned data**
|
||||
///
|
||||
/// ```
|
||||
/// use std::ptr;
|
||||
@ -2153,7 +2179,7 @@ pub macro addr_of($place:expr) {
|
||||
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
|
||||
/// ```
|
||||
///
|
||||
/// **Creating a pointer to uninitialized data:**
|
||||
/// **Correct usage: Creating a pointer to uninitialized data**
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::{ptr, mem::MaybeUninit};
|
||||
@ -2169,6 +2195,28 @@ pub macro addr_of($place:expr) {
|
||||
/// unsafe { f1_ptr.write(true); }
|
||||
/// let init = unsafe { uninit.assume_init() };
|
||||
/// ```
|
||||
///
|
||||
/// **Incorrect usage: Out-of-bounds fields projection**
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(C)]
|
||||
/// struct MyStruct {
|
||||
/// field1: i32,
|
||||
/// field2: i32,
|
||||
/// }
|
||||
///
|
||||
/// let ptr: *mut MyStruct = ptr::null_mut();
|
||||
/// let fieldptr = unsafe { ptr::addr_of_mut!((*ptr).field2) }; // Undefined Behavior ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// The field projection `.field2` would offset the pointer by 4 bytes,
|
||||
/// but the pointer is not in-bounds of an allocation for 4 bytes,
|
||||
/// so this offset is Undefined Behavior.
|
||||
/// See the [`offset`] docs for a full list of requirements for inbounds pointer arithmetic; the
|
||||
/// same requirements apply to field projections, even inside `addr_of_mut!`. (In particular, it
|
||||
/// makes no difference whether the pointer is null or dangling.)
|
||||
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
|
@ -9,6 +9,9 @@ pub mod cmath;
|
||||
pub mod locks;
|
||||
pub mod os_str;
|
||||
pub mod path;
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused_imports)]
|
||||
pub mod thread_local;
|
||||
|
||||
// FIXME(117276): remove this, move feature implementations into individual
|
||||
// submodules.
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
pub mod alloc;
|
||||
pub mod small_c_string;
|
||||
#[allow(unused_imports)]
|
||||
pub mod thread_local;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use super::abi;
|
||||
use super::thread_local_dtor::run_dtors;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::num::NonZero;
|
||||
@ -71,6 +71,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sleep(dur: Duration) {
|
||||
unsafe {
|
||||
|
@ -8,7 +8,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
cell::UnsafeCell,
|
||||
ffi::CStr,
|
||||
ffi::{CStr, CString},
|
||||
hint, io,
|
||||
mem::ManuallyDrop,
|
||||
num::NonZero,
|
||||
@ -204,6 +204,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
for timeout in dur2reltims(dur) {
|
||||
expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![cfg_attr(test, allow(dead_code))] // why is this necessary?
|
||||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::Duration;
|
||||
@ -133,6 +133,10 @@ impl Thread {
|
||||
// which succeeds as-is with the SGX target.
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
usercalls::wait_timeout(0, dur, || true);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::convert::TryInto;
|
||||
|
||||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::num::NonZero;
|
||||
@ -101,6 +101,10 @@ impl Thread {
|
||||
// contact the teeos rustzone team.
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
/// only main thread could wait for sometime in teeos
|
||||
pub fn sleep(dur: Duration) {
|
||||
let sleep_millis = dur.as_millis();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr::NonNull;
|
||||
@ -23,6 +23,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> =
|
||||
crate::os::uefi::env::boot_services().expect("can't sleep").cast();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::num::NonZero;
|
||||
@ -225,6 +225,44 @@ impl Thread {
|
||||
// Newlib, Emscripten, and VxWorks have no way to set a thread name.
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_name() -> Option<CString> {
|
||||
const TASK_COMM_LEN: usize = 16;
|
||||
let mut name = vec![0u8; TASK_COMM_LEN];
|
||||
let res = unsafe {
|
||||
libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
|
||||
};
|
||||
if res != 0 {
|
||||
return None;
|
||||
}
|
||||
name.truncate(name.iter().position(|&c| c == 0)?);
|
||||
CString::new(name).ok()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
|
||||
pub fn get_name() -> Option<CString> {
|
||||
let mut name = vec![0u8; libc::MAXTHREADNAMESIZE];
|
||||
let res = unsafe {
|
||||
libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
|
||||
};
|
||||
if res != 0 {
|
||||
return None;
|
||||
}
|
||||
name.truncate(name.iter().position(|&c| c == 0)?);
|
||||
CString::new(name).ok()
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos"
|
||||
)))]
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
pub fn sleep(dur: Duration) {
|
||||
let mut secs = dur.as_secs();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::Duration;
|
||||
@ -22,6 +22,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(_dur: Duration) {
|
||||
panic!("can't sleep");
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
use crate::num::NonZero;
|
||||
@ -134,6 +134,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let nanos = dur.as_nanos();
|
||||
assert!(nanos <= u64::MAX as u128);
|
||||
|
@ -344,6 +344,12 @@ compat_fn_with_fallback! {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
|
||||
}
|
||||
|
||||
// >= Win10 1607
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
|
||||
pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
|
||||
}
|
||||
|
||||
// >= Win8 / Server 2012
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
|
||||
pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
|
||||
|
@ -1923,6 +1923,7 @@ Windows.Win32.Foundation.HANDLE_FLAG_INHERIT
|
||||
Windows.Win32.Foundation.HANDLE_FLAG_PROTECT_FROM_CLOSE
|
||||
Windows.Win32.Foundation.HANDLE_FLAGS
|
||||
Windows.Win32.Foundation.HMODULE
|
||||
Windows.Win32.Foundation.LocalFree
|
||||
Windows.Win32.Foundation.MAX_PATH
|
||||
Windows.Win32.Foundation.NO_ERROR
|
||||
Windows.Win32.Foundation.NTSTATUS
|
||||
|
@ -379,6 +379,10 @@ extern "system" {
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn LocalFree(hmem: HLOCAL) -> HLOCAL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn MoveFileExW(
|
||||
lpexistingfilename: PCWSTR,
|
||||
@ -3441,6 +3445,7 @@ pub type HANDLE_FLAGS = u32;
|
||||
pub const HANDLE_FLAG_INHERIT: HANDLE_FLAGS = 1u32;
|
||||
pub const HANDLE_FLAG_PROTECT_FROM_CLOSE: HANDLE_FLAGS = 2u32;
|
||||
pub const HIGH_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 128u32;
|
||||
pub type HLOCAL = *mut ::core::ffi::c_void;
|
||||
pub type HMODULE = *mut ::core::ffi::c_void;
|
||||
pub type HRESULT = i32;
|
||||
pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32;
|
||||
|
@ -9,7 +9,7 @@ use crate::sys::handle::Handle;
|
||||
use crate::sys::stack_overflow;
|
||||
use crate::sys_common::FromInner;
|
||||
use crate::time::Duration;
|
||||
|
||||
use alloc::ffi::CString;
|
||||
use core::ffi::c_void;
|
||||
|
||||
use super::time::WaitableTimer;
|
||||
@ -71,6 +71,29 @@ impl Thread {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
unsafe {
|
||||
let mut ptr = core::ptr::null_mut();
|
||||
let result = c::GetThreadDescription(c::GetCurrentThread(), &mut ptr);
|
||||
if result < 0 {
|
||||
return None;
|
||||
}
|
||||
let name = String::from_utf16_lossy({
|
||||
let mut len = 0;
|
||||
while *ptr.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
core::slice::from_raw_parts(ptr, len)
|
||||
})
|
||||
.into_bytes();
|
||||
// Attempt to free the memory.
|
||||
// This should never fail but if it does then there's not much we can do about it.
|
||||
let result = c::LocalFree(ptr.cast::<c_void>());
|
||||
debug_assert!(result.is_null());
|
||||
if name.is_empty() { None } else { Some(CString::from_vec_unchecked(name)) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
|
||||
if rc == c::WAIT_FAILED {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::ffi::CStr;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::os::xous::ffi::{
|
||||
@ -113,6 +113,10 @@ impl Thread {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn get_name() -> Option<CString> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
// Because the sleep server works on units of `usized milliseconds`, split
|
||||
// the messages up into these chunks. This means we may run into issues
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
|
||||
|
||||
use crate::cell::OnceCell;
|
||||
use crate::sys;
|
||||
use crate::sys::thread::guard::Guard;
|
||||
use crate::thread::Thread;
|
||||
|
||||
@ -23,7 +24,8 @@ impl ThreadInfo {
|
||||
{
|
||||
THREAD_INFO
|
||||
.try_with(move |thread_info| {
|
||||
let thread = thread_info.thread.get_or_init(|| Thread::new(None));
|
||||
let thread =
|
||||
thread_info.thread.get_or_init(|| Thread::new(sys::thread::Thread::get_name()));
|
||||
f(thread, &thread_info.stack_guard)
|
||||
})
|
||||
.ok()
|
||||
|
@ -205,7 +205,7 @@ cfg_if::cfg_if! {
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "thread_local_internals", issue = "none")]
|
||||
pub mod local_impl {
|
||||
pub use crate::sys::common::thread_local::{thread_local_inner, Key, abort_on_dtor_unwind};
|
||||
pub use crate::sys::thread_local::{thread_local_inner, Key, abort_on_dtor_unwind};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,25 @@ fn test_named_thread_truncation() {
|
||||
result.unwrap().join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "tvos",
|
||||
target_os = "watchos"
|
||||
))]
|
||||
#[test]
|
||||
fn test_get_os_named_thread() {
|
||||
use crate::sys::thread::Thread;
|
||||
let handler = thread::spawn(|| {
|
||||
let name = c"test me please";
|
||||
Thread::set_name(name);
|
||||
assert_eq!(name, Thread::get_name().unwrap().as_c_str());
|
||||
});
|
||||
handler.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_invalid_named_thread() {
|
||||
|
@ -1680,7 +1680,7 @@ fn render_impl(
|
||||
write!(
|
||||
&mut doc_buffer,
|
||||
"{}",
|
||||
document_short(item, cx, link, parent, rendering_params.show_def_docs,)
|
||||
document_short(item, cx, link, parent, rendering_params.show_def_docs)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2043,15 +2043,13 @@ pub(crate) fn render_impl_summary(
|
||||
w.write_str("</h3>");
|
||||
|
||||
let is_trait = inner_impl.trait_.is_some();
|
||||
if is_trait {
|
||||
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
|
||||
write!(
|
||||
w,
|
||||
"<span class=\"item-info\">\
|
||||
<div class=\"stab portability\">{portability}</div>\
|
||||
</span>",
|
||||
);
|
||||
}
|
||||
if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
|
||||
write!(
|
||||
w,
|
||||
"<span class=\"item-info\">\
|
||||
<div class=\"stab portability\">{portability}</div>\
|
||||
</span>",
|
||||
);
|
||||
}
|
||||
|
||||
w.write_str("</section>");
|
||||
|
@ -33,6 +33,7 @@ use crate::html::format::{
|
||||
};
|
||||
use crate::html::layout::Page;
|
||||
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
||||
use crate::html::render::{document_full, document_item_info};
|
||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||
use crate::html::{highlight, static_files};
|
||||
|
||||
@ -818,8 +819,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
|
||||
info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
|
||||
let item_type = m.type_();
|
||||
let id = cx.derive_id(format!("{item_type}.{name}"));
|
||||
|
||||
let mut content = Buffer::empty_from(w);
|
||||
write!(&mut content, "{}", document(cx, m, Some(t), HeadingOffset::H5));
|
||||
write!(content, "{}", document_full(m, cx, HeadingOffset::H5));
|
||||
|
||||
let toggled = !content.is_empty();
|
||||
if toggled {
|
||||
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
|
||||
@ -836,8 +839,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str("</h4>");
|
||||
w.write_str("</section>");
|
||||
w.write_str("</h4></section>");
|
||||
document_item_info(cx, m, Some(t)).render_into(w).unwrap();
|
||||
if toggled {
|
||||
write!(w, "</summary>");
|
||||
w.push_buffer(content);
|
||||
|
24
tests/rustdoc/trait-item-info.rs
Normal file
24
tests/rustdoc/trait-item-info.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// This is a regression test for <https://github.com/rust-lang/rust/issues/121772>.
|
||||
// The goal is to ensure that the item information is always part of the `<summary>`
|
||||
// if there is one.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![feature(staged_api)]
|
||||
|
||||
#![unstable(feature = "test", issue = "none")]
|
||||
|
||||
// @has 'foo/trait.Foo.html'
|
||||
|
||||
#[stable(feature = "rust2", since = "2.2.2")]
|
||||
pub trait Foo {
|
||||
// @has - '//div[@class="methods"]/span[@class="item-info"]' 'bla'
|
||||
// Should not be in a `<details>` because there is no doc.
|
||||
#[unstable(feature = "bla", reason = "bla", issue = "111")]
|
||||
fn bla() {}
|
||||
|
||||
// @has - '//details[@class="toggle method-toggle"]/summary/span[@class="item-info"]' 'bar'
|
||||
// Should have a `<summary>` in the `<details>` containing the unstable info.
|
||||
/// doc
|
||||
#[unstable(feature = "bar", reason = "bla", issue = "222")]
|
||||
fn bar() {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user