diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 6116a6fd222b3..c45787f35aae6 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -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 = 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)); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 218891a7c67c7..b8cf72c2c73ff 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -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!("::{name}")) - .collect::>(), + traits.iter().map(|trait_str| format!("::{name}")), Applicability::HasPlaceholders, ); } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 054be89a7c4c5..b8cceebe1036e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -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::>(), + items.iter().map(|(_, name, args)| suggestion(name, *args)), Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 2978491d646e8..f2cf6fe613c33 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -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]; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 327884c8414a4..d008346af6942 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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::>(), + items.iter().map(|(_, name, len)| suggestion(name, *len)), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways, ); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index bc2bae9da6131..3fa409eefffcd 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -57,7 +57,7 @@ impl<'tcx> ObligationStorage<'tcx> { fn take_pending(&mut self) -> Vec> { let mut obligations = mem::take(&mut self.pending); - obligations.extend(self.overflowed.drain(..)); + obligations.append(&mut self.overflowed); obligations } diff --git a/library/core/src/error.rs b/library/core/src/error.rs index ded17e69bd9c6..a3f2b767054e1 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -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. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fc5b08c9801a8..018efd4b9b34b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2071,11 +2071,16 @@ impl 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 fmt::Debug for F { /// /// # Example /// +/// **Correct usage: Creating a pointer to unaligned data** +/// /// ``` /// use std::ptr; /// @@ -2101,9 +2108,27 @@ impl 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)] diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index d77ac7eb027dc..81200e0061e05 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -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. diff --git a/library/std/src/sys/pal/common/mod.rs b/library/std/src/sys/pal/common/mod.rs index b35c5d30b4113..29fc0835d7666 100644 --- a/library/std/src/sys/pal/common/mod.rs +++ b/library/std/src/sys/pal/common/mod.rs @@ -12,8 +12,6 @@ pub mod alloc; pub mod small_c_string; -#[allow(unused_imports)] -pub mod thread_local; #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index fee80c02d4a6f..cf45b9c23962c 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -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 { + None + } + #[inline] pub fn sleep(dur: Duration) { unsafe { diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 9c1387bf4083a..814a102dd09ae 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -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 { + None + } + pub fn sleep(dur: Duration) { for timeout in dur2reltims(dur) { expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index c797fde7fbdca..77f68bf73348f 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -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 { + None + } + pub fn sleep(dur: Duration) { usercalls::wait_timeout(0, dur, || true); } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index 77f9040ead540..b76bcf9bbb0af 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -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 { + None + } + /// only main thread could wait for sometime in teeos pub fn sleep(dur: Duration) { let sleep_millis = dur.as_millis(); diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs index 3d8fa27251f01..b3a4f9c53e36c 100644 --- a/library/std/src/sys/pal/uefi/thread.rs +++ b/library/std/src/sys/pal/uefi/thread.rs @@ -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 { + None + } + pub fn sleep(dur: Duration) { let boot_services: NonNull = crate::os::uefi::env::boot_services().expect("can't sleep").cast(); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 864de31c6ebfc..2af6382f3daee 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -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 { + 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 { + 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 { + None + } + #[cfg(not(target_os = "espidf"))] pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs index cd1ae7f7d11cd..b3a91ee1d4cb6 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/pal/unsupported/thread.rs @@ -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 { + None + } + pub fn sleep(_dur: Duration) { panic!("can't sleep"); } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index 77d8b4378e7d5..4b116052f8f8e 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -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 { + None + } + pub fn sleep(dur: Duration) { let nanos = dur.as_nanos(); assert!(nanos <= u64::MAX as u128); diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index b007796722baf..afa9240940494 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -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) -> () { diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index ab2a8caf5dfd9..d008141153028 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -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 diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 8eb779373f7e4..96773d91e990c 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -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; diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 0f709e2ec7ba7..a8f1e9b726b1c 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -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 { + 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::()); + 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 { diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index 21f5954d6e2d2..f95ceb7343bd1 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -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 { + 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 diff --git a/library/std/src/sys/pal/common/thread_local/fast_local.rs b/library/std/src/sys/thread_local/fast_local.rs similarity index 100% rename from library/std/src/sys/pal/common/thread_local/fast_local.rs rename to library/std/src/sys/thread_local/fast_local.rs diff --git a/library/std/src/sys/pal/common/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs similarity index 100% rename from library/std/src/sys/pal/common/thread_local/mod.rs rename to library/std/src/sys/thread_local/mod.rs diff --git a/library/std/src/sys/pal/common/thread_local/os_local.rs b/library/std/src/sys/thread_local/os_local.rs similarity index 100% rename from library/std/src/sys/pal/common/thread_local/os_local.rs rename to library/std/src/sys/thread_local/os_local.rs diff --git a/library/std/src/sys/pal/common/thread_local/static_local.rs b/library/std/src/sys/thread_local/static_local.rs similarity index 100% rename from library/std/src/sys/pal/common/thread_local/static_local.rs rename to library/std/src/sys/thread_local/static_local.rs diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index 8d51732e03588..ec1428ea40ec6 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -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() diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 76af7fec92648..85de2980133d5 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -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}; } } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 5d6b9e94ee91b..efd06c8df6e29 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -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() { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ac7ae291d29b3..fe83095f944ab 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -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(""); let is_trait = inner_impl.trait_.is_some(); - if is_trait { - if let Some(portability) = portability(&i.impl_item, Some(parent)) { - write!( - w, - "\ -
{portability}
\ -
", - ); - } + if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) { + write!( + w, + "\ +
{portability}
\ +
", + ); } w.write_str(""); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 71186319e07dd..d588f219739fe 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -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(""); - w.write_str(""); + w.write_str(""); + document_item_info(cx, m, Some(t)).render_into(w).unwrap(); if toggled { write!(w, ""); w.push_buffer(content); diff --git a/tests/rustdoc/trait-item-info.rs b/tests/rustdoc/trait-item-info.rs new file mode 100644 index 0000000000000..53a4c6917b9b0 --- /dev/null +++ b/tests/rustdoc/trait-item-info.rs @@ -0,0 +1,24 @@ +// This is a regression test for . +// The goal is to ensure that the item information is always part of the `` +// 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 `
` 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 `` in the `
` containing the unstable info. + /// doc + #[unstable(feature = "bar", reason = "bla", issue = "222")] + fn bar() {} +}