diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index aa204a20e2d57..c3dff49be9927 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1254,7 +1254,7 @@ fn check_overriding_final_trait_item<'tcx>( trait_item: ty::AssocItem, impl_item: ty::AssocItem, ) { - if trait_item.defaultness(tcx).is_final() { + if trait_item.is_fn() && trait_item.defaultness(tcx).is_final() { tcx.dcx().emit_err(diagnostics::OverridingFinalTraitFunction { impl_span: tcx.def_span(impl_item.def_id), trait_span: tcx.def_span(trait_item.def_id), diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 92bc577f59201..ddf5600f76659 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -641,42 +641,99 @@ pub fn source_span_for_markdown_range_inner( let mut start_bytes = 0; let mut end_bytes = 0; + let span_of_all_fragments: Span = span_of_fragments(fragments)?; + + let mut prev_lines_bytes = 0; 'outer: for (line_no, md_line) in md_lines.enumerate() { loop { let source_line = src_lines.next()?; - match source_line.find(md_line) { - Some(offset) => { - if line_no == starting_line { - start_bytes += offset; + let source_line_len = u32::try_from(source_line.len()).unwrap(); + let source_line_span = + span_of_all_fragments.split_at(prev_lines_bytes).1.split_at(source_line_len).0; + let fragment = fragments + .iter() + // `source_line_span` might contain indentation that `fragment.span` doesn't contain + .find(|fragment| fragment.span.overlaps(source_line_span)); + // Since we're counting bytes, `prev_line_bytes` includes the "\n". + prev_lines_bytes += source_line_len + 1; + if let Some(fragment) = fragment + && let Some(offset) = source_line.find(md_line) + { + if fragment.span.lo() > source_line_span.lo() + && source_line + [..usize::try_from(fragment.span.lo().0 - source_line_span.lo().0).unwrap()] + .chars() + .any(|c| !c.is_whitespace()) + { + // Make sure anything between the start of this line and the fragment itself is just indentation. + // Because source_line is built by splitting the span that covers all fragments, this only finds + // characters *between* doc comments, not characters before or after doc comments. + // + // 1| /** doc */ + // 2| #[inline] /** doc2 */ + // ^^^^^^^^^ + // | this + // + // 3| fn foo() {} + return None; + } + if fragment.span.hi() < source_line_span.hi() + && source_line + [usize::try_from(fragment.span.hi().0 - source_line_span.lo().0).unwrap()..] + .chars() + .any(|c| !c.is_whitespace()) + { + // Make sure anything between the start of this line and the fragment itself is just indentation. + // Because source_line is built by splitting the span that covers all fragments, this only finds + // characters *between* doc comments, not characters before or after doc comments. + // 1| /** doc */ #[inline] + // ^^^^^^^^^ + // | this + // + // 2| /** doc2 */ + // 3| fn foo() {} + return None; + } + if line_no == starting_line { + start_bytes += offset; - if starting_line == ending_line { - break 'outer; - } - } else if line_no == ending_line { - end_bytes += offset; + if starting_line == ending_line { break 'outer; - } else if line_no < starting_line { - start_bytes += source_line.len() - md_line.len(); - } else { - end_bytes += source_line.len() - md_line.len(); } - break; + } else if line_no == ending_line { + end_bytes += offset; + break 'outer; + } else if line_no < starting_line { + start_bytes += source_line.len() - md_line.len(); + } else { + end_bytes += source_line.len() - md_line.len(); } - None => { - // Since this is a source line that doesn't include a markdown line, - // we have to count the newline that we split from earlier. - if line_no <= starting_line { - start_bytes += source_line.len() + 1; - } else { - end_bytes += source_line.len() + 1; - } + break; + } else { + // Since this is a source line that doesn't include a markdown line, + // we have to count it and its newline as non-markdown bytes. + if line_no <= starting_line { + start_bytes += source_line.len() + 1; + } else if source_line.chars().any(|c| !c.is_whitespace()) { + // We're past the first line, but haven't found the last line, + // but we found a non-empty non-markdown line. + // This could be an attribute, and we don't want a diagnostic + // suggesting to delete that attribute, so we return None to be safe. + // 1| /** doc */ + // 2 | #[inline] + // ^^^^^^^^^ + // | this + // 3| /** doc2 */ + // 4| fn foo() {} + return None; + } else { + end_bytes += source_line.len() + 1; } } } } - let span = span_of_fragments(fragments)?; - let src_span = span.from_inner(InnerSpan::new( + let src_span = span_of_all_fragments.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, )); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index e4a2aaff86aed..f6887c18075a4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -1,13 +1,14 @@ use std::fmt; use rustc_data_structures::intern::Interned; -use rustc_errors::{Diag, IntoDiagArg}; +use rustc_errors::{Applicability, Diag, IntoDiagArg}; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode}; -use rustc_middle::ty::{self, GenericArgsRef, RePlaceholder, Region, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, TyCtxt}; use tracing::{debug, instrument}; use crate::diagnostics::{ @@ -379,6 +380,50 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } } + // When the mismatched trait is an Fn-trait and the self type is a closure with + // unannotated parameters, suggest adding explicit type annotations. This turns + // the confusing lifetime-generality error into an actionable hint, e.g.: + // |buf| → |buf: &mut [u8]| + if self.tcx().is_fn_trait(trait_def_id) { + let actual_self_ty = self.cx.resolve_vars_if_possible( + ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args).self_ty(), + ); + if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind() + && let Some(local_def_id) = closure_def_id.as_local() + && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = + self.tcx().hir_node_by_def_id(local_def_id) + { + let body = self.tcx().hir_body(closure.body); + // For Fn traits, args[1] is the tupled input types (e.g. `(&mut [u8],)`). + let expected_input_tys = expected_args.type_at(1); + if let ty::Tuple(input_tys) = *expected_input_tys.kind() { + let suggestions: Vec<_> = body + .params + .iter() + .zip(input_tys.iter()) + .filter_map(|(param, ty)| { + // ty_span == pat.span means no explicit type annotation was written. + if param.ty_span == param.pat.span + && ty.is_suggestable(self.tcx(), false) + { + Some((param.pat.span.shrink_to_hi(), format!(": {ty}"))) + } else { + None + } + }) + .collect(); + if !suggestions.is_empty() { + let msg = if suggestions.len() == 1 { + "consider adding an explicit type annotation to the closure's argument" + } else { + "consider adding explicit type annotations to the closure's arguments" + }; + err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); + } + } + } + } + err } diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 102fb19efc8ea..806f67728efb8 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -57,21 +57,91 @@ impl fmt::Display for AllocError { /// allocator does not support this (like jemalloc) or responds by returning a null pointer /// (such as `libc::malloc`), this must be caught by the implementation. /// +/// ### Equivalent allocators +/// +/// Multiple allocator values can sometimes be interchangeable with each other. +/// When this is the case, we refer to those allocators as being *equivalent* to +/// each other. +/// +/// The following conditions are sufficient conditions for allocators to be equivalent. +/// * An allocator is equivalent to itself. (Equivalence is reflexive.) +/// * If an allocator is equivalent to a second allocator, then +/// the second allocator is also equivalent to the first. (Equivalence is symmetric.) +/// * If an allocator is equivalent to a second allocator, and +/// the second allocator is equivalent to a third allocator, then +/// the first allocator is also equivalent to the third allocator. +/// (Equivalence is transitive.) +/// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change +/// what the allocator is equivalent to. +/// * Copying or cloning allocator results in an allocator that's +/// equivalent to the initial allocator. +/// +/// Additionally, implementors of `Allocator` may specify additional equivalences +/// between allocators. It is the responsibility of such implementors to make sure +/// that equivalent allocators have "compatible" `Allocator` implementations. +/// In particular, the standard library specifies the following equivalences: +/// * A reference to an allocator (either `&` or `&mut`) is equivalent to +/// the allocator being referenced. +/// * A `Box`, `Rc`, or `Arc` containing an allocator is equivalent to +/// the allocator inside. +/// * All `Global` allocator instances are equivalent with each other. +/// * All `System` allocator instances are equivalent with each other. +/// +/// Note: Currently, the interaction between cloning and unsize-coercing allocators +/// is unsound, and there is ongoing discussion on how to revise the `Allocator` trait +/// to fix this. See [#156920]. +/// +/// [#156920]: https://github.com/rust-lang/rust/issues/156920 +/// /// ### Currently allocated memory /// -/// Some of the methods require that a memory block is *currently allocated* by an allocator. +/// Some of the methods require that a memory block is *currently allocated* by some specific allocator. /// This means that: -/// * the starting address for that memory block was previously -/// returned by [`allocate`], [`grow`], or [`shrink`], and -/// * the memory block has not subsequently been deallocated. +/// * the starting address for that memory block was previously returned by +/// the [`allocate`], [`allocate_zeroed`], [`grow`], [`grow_zeroed`], or [`shrink`] methods, +/// called on an allocator that's equivalent to this specific allocator; and +/// * the memory block has not subsequently been [*invalidated*]. +/// +/// [*invalidated*]: #invalidating-memory-blocks +/// +/// ### Invalidating memory blocks /// -/// A memory block is deallocated by a call to [`deallocate`], -/// or by a call to [`grow`] or [`shrink`] that returns `Ok`. -/// A call to `grow` or `shrink` that returns `Err`, -/// does not deallocate the memory block passed to it. +/// A memory block that is currently allocated becomes *invalidated* when one +/// of the following happens: +/// * The memory block is deallocated. This occurs when the memory block +/// is passed as an argument to a [`deallocate`] call, or when it is passed +/// as an argument to a [`grow`], [`grow_zeroed`] or [`shrink`] call that returns `Ok`. +/// * All (equivalent) allocators that this memory block is allocated with, +/// each has one of the following happen to them: +/// * The allocator's destructor runs. +/// * The allocator is mutated through public API taking `&mut` access. +/// * One of the borrow-checker lifetimes in the allocator's type expires. +/// +/// Note that these conditions imply that a collection may ensure that +/// any specific currently allocated memory block won't be invalidated, by: +/// * not deallocating that memory block, +/// * owning an allocator that memory block is allocated with, and +/// * not publicly exposing `&mut` access to that allocator. +/// +/// Also note that safe public API of an allocator with `&` access is not +/// allowed to invalidate its memory blocks. Furthermore, unsafe public API +/// of an allocator with `&` access must document that they invalidate +/// memory blocks (e.g., by calling `deallocate`) if they do. Therefore, +/// collections may safely expose `&` access to its allocator. +/// +/// Also note that, even in cases where are other "alive" allocators known to be +/// equivalent to a given collection's allocator, most collections still should +/// not publicly expose `&mut` access to its allocator. The fact that there are +/// other "alive" allocators would prevent this `&mut` access from invalidating +/// the collection's memory block, but public `&mut` access is still likely to +/// be unsound, since a user could replace the collection's allocator with +/// a non-equivalent allocator, causing the collection to deallocate its memory +/// with the wrong allocator. /// /// [`allocate`]: Allocator::allocate +/// [`allocate_zeroed`]: Allocator::allocate_zeroed /// [`grow`]: Allocator::grow +/// [`grow_zeroed`]: Allocator::grow_zeroed /// [`shrink`]: Allocator::shrink /// [`deallocate`]: Allocator::deallocate /// @@ -82,23 +152,20 @@ impl fmt::Display for AllocError { /// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and /// * [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout used to allocate the block, and -/// - `max` is the actual size returned from [`allocate`], [`grow`], or [`shrink`]. +/// - `max` is the actual size returned from [`allocate`], [`allocate_zeroed`], +/// [`grow`], [`grow_zeroed`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size /// /// # Safety /// -/// Memory blocks that are [*currently allocated*] by an allocator, -/// must point to valid memory, and retain their validity until either: -/// - the memory block is deallocated, or -/// - the allocator is dropped. -/// -/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it. -/// A copied or cloned allocator must behave like the original allocator. -/// -/// A memory block which is [*currently allocated*] may be passed to -/// any method of the allocator that accepts such an argument. +/// Implementors of `Allocator` must ensure that a memory block that +/// is [*currently allocated*] by the allocator points to valid memory, +/// until that memory block is [*invalidated*]. The implementor must also +/// not violate this invariant of `Allocator` via allocator equivalences +/// that are in the implementor's control (e.g., via a misbehaving +/// `impl Clone for Box`). /// /// Additionally, any memory block returned by the allocator must /// satisfy the allocation invariants described in `core::ptr`. @@ -107,7 +174,9 @@ impl fmt::Display for AllocError { /// /// This ensures that pointer arithmetic within the allocation /// (for example, `ptr.add(len)`) cannot overflow the address space. +/// /// [*currently allocated*]: #currently-allocated-memory +/// [*invalidated*]: #invalidating-memory-blocks #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub const unsafe trait Allocator { @@ -118,11 +187,13 @@ pub const unsafe trait Allocator { /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// - /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of: - /// - the borrow-checker lifetime of the allocator type itself. - /// - as long as the allocator and all its clones have not been dropped. + /// Note that the returned block of memory is considered [*currently allocated*] + /// with this allocator (and equivalent allocators). + /// Therefore, it is the responsibility of implementors of `Allocator` to make sure that + /// this block of memory points to valid memory until the block is [*invalidated*] /// /// [*currently allocated*]: #currently-allocated-memory + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// @@ -178,13 +249,12 @@ pub const unsafe trait Allocator { /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// - /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been - /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the - /// allocation was grown in-place. The newly returned pointer is the only valid pointer - /// for accessing this memory now. + /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. + /// The old `ptr` must not be used to access the memory, even if the allocation was grown in-place. + /// The newly returned pointer is the only valid pointer for accessing this memory now. /// - /// If this method returns `Err`, then ownership of the memory block has not been transferred to - /// this allocator, and the contents of the memory block are unaltered. + /// If this method returns `Err`, then the memory block has not been *invalidated*, + /// and the contents of the memory block are unaltered. /// /// # Safety /// @@ -196,6 +266,7 @@ pub const unsafe trait Allocator { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// @@ -305,13 +376,13 @@ pub const unsafe trait Allocator { /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// - /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been - /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the - /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer - /// for accessing this memory now. /// - /// If this method returns `Err`, then ownership of the memory block has not been transferred to - /// this allocator, and the contents of the memory block are unaltered. + /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. + /// The old `ptr` must not be used to access the memory, even if the allocation was shrunk in-place. + /// The newly returned pointer is the only valid pointer for accessing this memory now. + /// + /// If this method returns `Err`, then the memory block has not been *invalidated*, + /// and the contents of the memory block are unaltered. /// /// # Safety /// @@ -323,6 +394,7 @@ pub const unsafe trait Allocator { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 304f2f23828de..e13f44d6fc9bd 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -53,7 +53,15 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s let mut len = SUN_PATH_OFFSET + bytes.len(); match bytes.get(0) { Some(&0) | None => {} - Some(_) => len += 1, + Some(_) => { + // on QNX7.1 and QNX8 the `len` value returned by the SUN_LEN + // macro in its libc does not include the null byte in the count so + // don't add it here to match what a C program passes to bind(2) and + // similar functions + if cfg!(not(any(target_os = "qnx", target_env = "nto71"))) { + len += 1 + } + } } Ok((addr, len as libc::socklen_t)) } @@ -247,7 +255,13 @@ impl SocketAddr { } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + // the value returned by getsockname(2) and similar on QNX7.1 and + // QNX8 does not count the NUL byte terminator of the path string, + // which matches the behavior of the SUN_LEN macro in libc, but + // other OSes do count the NUL byte so adjust accordingly + let end = + if cfg!(any(target_os = "qnx", target_env = "nto71")) { len } else { len - 1 }; + AddressKind::Pathname(OsStr::from_bytes(&path[..end]).as_ref()) } } } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4dfa06d74ce7e..a50b10539ebf5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -256,6 +256,7 @@ impl UnixStream { target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_os = "qnx", target_vendor = "apple", target_os = "cygwin" ))] diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index f703fc6d54c02..3ba4b44d2f1ef 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -9,6 +9,7 @@ use crate::os::cygwin::net::{SocketAddrExt, UnixSocketExt}; use crate::os::linux::net::{SocketAddrExt, UnixSocketExt}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::os::unix::io::AsRawFd; +use crate::path::Path; use crate::test_helpers::tmpdir; use crate::thread; use crate::time::Duration; @@ -22,6 +23,12 @@ macro_rules! or_panic { }; } +#[test] +fn sock_addr_from_pathname() { + let address = or_panic!(SocketAddr::from_pathname("/path/to/socket")); + assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); +} + #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] @@ -32,6 +39,7 @@ fn basic() { let msg2 = b"world!"; let listener = or_panic!(UnixListener::bind(&socket_path)); + assert_eq!(Some(&*socket_path), listener.local_addr().unwrap().as_pathname()); let thread = thread::spawn(move || { let mut stream = or_panic!(listener.accept()).0; let mut buf = [0; 5]; @@ -79,6 +87,8 @@ fn pair() { let msg2 = b"world!"; let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + assert!(s1.local_addr().unwrap().is_unnamed()); + assert!(s2.peer_addr().unwrap().is_unnamed()); let thread = thread::spawn(move || { // s1 must be moved in or the test will hang! let mut buf = [0; 5]; diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 3a35aa3006d75..f55c821dfb7bc 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -19,9 +19,9 @@ cfg_select! { type GroupId = u16; } any(target_os = "nto", target_os = "qnx") => { - // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP. + // Both IDs are signed, see `sys/target_nto.h` of the QNX SDP. // Only positive values should be used, see e.g. - // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html + // https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html type UserId = i32; type GroupId = i32; } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 26296b5d169a1..9c4ba9f5f388a 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -177,9 +177,9 @@ impl Timespec { }) } - // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait + // On QNX, the maximum timespec for e.g. pthread_cond_timedwait // is 2^64 nanoseconds - #[cfg(target_os = "nto")] + #[cfg(any(target_os = "nto", target_os = "qnx"))] pub(in crate::sys) fn to_timespec_capped(&self) -> Option { // Check if timeout in nanoseconds would fit into an u64 if (self.tv_nsec.as_inner() as u64) diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index c2ecc6e5da3d4..7d916b843f24e 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -285,7 +285,7 @@ pub fn current_exe() -> io::Result { #[cfg(any(target_os = "nto", target_os = "qnx"))] pub fn current_exe() -> io::Result { let mut e = crate::fs::read("/proc/self/exefile")?; - // Current versions of QNX Neutrino provide a null-terminated path. + // Current versions of QNX SDP provide a null-terminated path. // Ensure the trailing null byte is not returned here. if let Some(0) = e.last() { e.pop(); diff --git a/library/std/src/sys/process/unix/common/tests.rs b/library/std/src/sys/process/unix/common/tests.rs index 5f71bf051f8a8..bc1d158b74861 100644 --- a/library/std/src/sys/process/unix/common/tests.rs +++ b/library/std/src/sys/process/unix/common/tests.rs @@ -99,8 +99,13 @@ fn test_process_group_posix_spawn() { cmd.stdout(Stdio::MakePipe); let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + // Check that we can kill its process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -127,8 +132,18 @@ fn test_process_group_no_posix_spawn() { cmd.stdout(Stdio::MakePipe); let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Check that we can kill its process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -154,9 +169,19 @@ fn test_setsid_posix_spawn() { let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); unsafe { + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Setsid will create a new session and process group, so check that // we can kill the process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -184,9 +209,19 @@ fn test_setsid_no_posix_spawn() { cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec rather than posix spawn. let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Setsid will create a new session and process group, so check that // we can kill the process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index dc11f44574a5f..34bf78e8bb325 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -193,10 +193,10 @@ impl Command { cvt(libc::fork()) } - // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened + // On QNX SDP, fork can fail with EBADF in case "another thread might have opened // or closed a file descriptor while the fork() was occurring". // Documentation says "... or try calling fork() again". This is what we do here. - // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html + // See also https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/f/fork.html #[cfg(any(target_os = "nto", target_os = "qnx"))] unsafe fn do_fork(&mut self) -> Result { use crate::sys::io::errno; @@ -553,10 +553,10 @@ impl Command { } } - // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened + // On QNX SDP, posix_spawnp can fail with EBADF in case "another thread might have opened // or closed a file descriptor while the posix_spawn() was occurring". // Documentation says "... or try calling posix_spawn() again". This is what we do here. - // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html + // See also https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html #[cfg(any(target_os = "nto", target_os = "qnx"))] unsafe fn retrying_libc_posix_spawnp( pid: *mut pid_t, @@ -756,7 +756,7 @@ impl Command { if self.get_setsid() { cfg_select! { all(target_os = "linux", target_env = "gnu") => { - flags |= libc::POSIX_SPAWN_SETSID; + flags |= libc::POSIX_SPAWN_SETSID as i32; } _ => { return Ok(None); diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index e52ffff165beb..2dbb0314cb271 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -278,7 +278,7 @@ pub fn available_parallelism() -> io::Result> { Ok(unsafe { NonZero::new_unchecked(cpus as usize) }) } - target_os = "nto" => { + any(target_os = "nto", target_os = "qnx") => { unsafe { use libc::_syspage_ptr; if _syspage_ptr.is_null() { @@ -347,7 +347,7 @@ pub fn current_os_id() -> Option { let id: libc::pid_t = unsafe { gettid() }; Some(id as u64) } - target_os = "nto" => { + any(target_os = "nto", target_os = "qnx") => { // SAFETY: FFI call with no preconditions. let id: libc::pid_t = unsafe { libc::gettid() }; Some(id as u64) @@ -392,6 +392,7 @@ pub fn current_os_id() -> Option { #[cfg(any( target_os = "linux", target_os = "nto", + target_os = "qnx", target_os = "solaris", target_os = "illumos", target_os = "vxworks", @@ -484,14 +485,14 @@ pub fn set_name(name: &CStr) { } } -#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] +#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto", target_os = "qnx"))] pub fn set_name(name: &CStr) { weak!( fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int; ); if let Some(f) = pthread_setname_np.get() { - #[cfg(target_os = "nto")] + #[cfg(any(target_os = "nto", target_os = "qnx"))] const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize; #[cfg(any(target_os = "solaris", target_os = "illumos"))] const THREAD_NAME_MAX: usize = 32; diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs index 0a10925ae6499..37ccb10337cf9 100644 --- a/library/std/src/sys/thread_local/key/racy.rs +++ b/library/std/src/sys/thread_local/key/racy.rs @@ -21,12 +21,12 @@ pub struct LazyKey { // Define a sentinel value that is likely not to be returned // as a TLS key. -#[cfg(not(target_os = "nto"))] +#[cfg(not(any(target_os = "nto", target_os = "qnx")))] const KEY_SENTVAL: usize = 0; -// On QNX Neutrino, 0 is always returned when currently not in use. -// Using 0 would mean to always create two keys and remote the first +// On QNX SDP, 0 is always returned when currently not in use. +// Using 0 would mean to always create two keys and remove the first // one (with value of 0) immediately afterwards. -#[cfg(target_os = "nto")] +#[cfg(any(target_os = "nto", target_os = "qnx"))] const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl LazyKey { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 4302950d2e3e8..321fc4440f330 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -434,7 +434,7 @@ impl LocalKey { /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return an [`AccessError`]. + /// in a destructor), this function may return an [`AccessError`]. /// /// # Panics /// diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index eb3f664e51b35..b61c7b18bad01 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/157557 +Last change is for: https://github.com/rust-lang/rust/pull/157385 diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index f58b385db87ac..74f1a0abdde8e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -474,7 +474,7 @@ auto: - name: dist-x86_64-apple env: SCRIPT: >- - ./x.py dist bootstrap + ./x.py dist bootstrap enzyme --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 280b0b195634e..ce4d55c2d2b00 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -275,9 +275,9 @@ target | std | host | notes [`aarch64-unknown-linux-pauthtest`](platform-support/aarch64-unknown-linux-pauthtest.md) | ✓ | ✓ | ARM64 PAC ELF ABI [`aarch64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | ARM64 Managarm [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD -[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | -[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | -[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX SDP 7.0 | +[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 7.1 with default network stack (io-pkt) | +[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 7.1 with new network stack (io-sock) | [`aarch64-unknown-qnx`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 8.0+ | [`aarch64-unknown-nuttx`](platform-support/nuttx.md) | ✓ | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD @@ -340,7 +340,7 @@ target | std | host | notes [`i586-unknown-redox`](platform-support/redox.md) | ✓ | | 32-bit x86 Redox OS (PentiumPro) [^x86_32-floats-x87] [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] [`i686-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | 32-bit x86 OpenEmbedded/Yocto Linux (GNU) -[`i686-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX SDP 7.0 (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-helenos`](platform-support/helenos.md) | ✓ | | HelenOS IA-32 (see docs for pending issues) [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-return-ABI] @@ -450,8 +450,8 @@ target | std | host | notes [`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178 [`x86_64-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | x86 64-bit OpenEmbedded/Yocto Linux (GNU) [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin | -[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | -[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 7.1 with default network stack (io-pkt) | +[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 7.1 with new network stack (io-sock) | [`x86_64-pc-qnx`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 8.0+ | [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.5 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index c9258f9558de8..4d88878e2e07c 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -83,49 +83,23 @@ For conditional compilation, the following QNX specific attributes are defined: ```toml profile = "compiler" change-id = 999999 - ``` - -2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host - - Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. - Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). - - To compile for QNX, environment variables must be set to use the correct tools and compiler switches: - - `CC_=qcc` - - `CFLAGS_=` - - `CXX_=qcc` - - `AR_=` - - With: - - - `` target triplet using underscores instead of hyphens, e.g. `aarch64_unknown_nto_qnx710` - - `` - - - `-Vgcc_ntox86_cxx` for x86 (32 bit) - - `-Vgcc_ntox86_64_cxx` for x86_64 (64 bit) - - `-Vgcc_ntoaarch64le_cxx` for Aarch64 (64 bit) + [build] + host = ["x86_64-unknown-linux-gnu"] + target = ["x86_64-unknown-linux-gnu", "aarch64-unknown-nto-qnx710"] + ``` - - `` +2. Compile the Rust toolchain with the QNX SDP environment loaded - - `ntox86-ar` for x86 (32 bit) - - `ntox86_64-ar` for x86_64 (64 bit) - - `ntoaarch64-ar` for Aarch64 (64 bit) + As noted above, we need the right environment variables for QNX SDP to work, + and for `qcc` to be in your system PATH. Typically this is done by sourcing + the `qnxsdp-env.sh` file (or equivalent for your host platform). - Example to build the Rust toolchain including a standard library for x86_64-linux-gnu and Aarch64-QNX-7.1: + To build on Linux, you would run: ```bash - export build_env=' - CC_aarch64_unknown_nto_qnx710=qcc - CFLAGS_aarch64_unknown_nto_qnx710=-Vgcc_ntoaarch64le_cxx - CXX_aarch64_unknown_nto_qnx710=qcc - AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar - ' - - env $build_env \ - ./x.py build \ - --target x86_64-unknown-linux-gnu,aarch64-unknown-nto-qnx710 \ - rustc library/core library/alloc library/std + source ~/qnx710/qnxsdp-env.sh + ./x.py build rustc library/core library/alloc library/std ``` ## Building Rust programs @@ -147,7 +121,7 @@ change calling conventions or memory layout. The test suites of the Rust compiler and standard library can be executed much like other Rust targets. The environment for testing should match the one used -during compiler compilation (refer to `build_env` and `qcc`/`PATH` above) with +during compiler compilation (refer to notes on `qnxsdp-env.sh` above) with the addition of the `TEST_DEVICE_ADDR` environment variable. The `TEST_DEVICE_ADDR` variable controls the remote runner and should point to a target running the `remote-test-server` executable. @@ -158,8 +132,8 @@ target maintainers which can be seen in the following example. To run all tests on a x86_64 QNX Neutrino 7.1 target: ```bash +source ~/qnx710/qnxsdp-env.sh export TEST_DEVICE_ADDR="1.2.3.4:12345" # must address the test target, can be a SSH tunnel -export build_env= # Disable tests that only work on the host or don't make sense for this target. # See also: @@ -174,11 +148,10 @@ export exclude_tests=' --exclude rustc --exclude rustdoc' -env $build_env \ - ./x.py test \ - $exclude_tests \ - --stage 1 \ - --target x86_64-pc-nto-qnx710 +./x.py test \ + $exclude_tests \ + --stage 1 \ + --target x86_64-pc-nto-qnx710 ``` ### Rust std library test suite diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 8da21f100c6a3..cd7b7caac69ad 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -80,7 +80,7 @@ fn check_redundant_explicit_link<'md>( hir_id: HirId, doc: &'md str, resolutions: &DocLinkResMap, -) -> Option<()> { +) { let mut broken_line_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); let mut offset_iter = Parser::new_with_broken_link_callback( doc, @@ -115,7 +115,7 @@ fn check_redundant_explicit_link<'md>( } if dest_url.ends_with(resolvable_link) || resolvable_link.ends_with(&*dest_url) { - match link_type { + let check_result = match link_type { LinkType::Inline | LinkType::ReferenceUnknown => { check_inline_or_reference_unknown_redundancy( cx, @@ -127,27 +127,52 @@ fn check_redundant_explicit_link<'md>( dest_url.to_string(), link_data, if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, - ); - } - LinkType::Reference => { - check_reference_redundancy( - cx, - item, - hir_id, - doc, - resolutions, - link_range, - &dest_url, - link_data, - ); + ) } - _ => {} + LinkType::Reference => check_reference_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + &dest_url, + link_data, + ), + _ => Ok(()), + }; + if let Err(lint) = check_result { + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + item.attr_span(cx.tcx), + lint, + ); } } } } +} - None +struct RedundantExplicitLinksWithoutSuggestion { + attr_span: Span, + display_link: String, + dest_link: String, +} + +impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinksWithoutSuggestion { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { attr_span, display_link, dest_link } = self; + + Diag::new(dcx, level, "redundant explicit link target") + .with_span_label( + attr_span, + format!("explicit target `{dest_link}` is redundant because label `{display_link}` resolves to same destination") + ) + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ) + } } /// FIXME(ChAoSUnItY): Too many arguments. @@ -161,7 +186,7 @@ fn check_inline_or_reference_unknown_redundancy( dest: String, link_data: LinkData, (open, close): (u8, u8), -) -> Option<()> { +) -> Result<(), RedundantExplicitLinksWithoutSuggestion> { struct RedundantExplicitLinks { explicit_span: Span, display_span: Span, @@ -196,42 +221,65 @@ fn check_inline_or_reference_unknown_redundancy( } } - let (resolvable_link, resolvable_link_range) = - (&link_data.resolvable_link?, &link_data.resolvable_link_range?); - let (dest_res, display_res) = - (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); + let (Some(resolvable_link), Some(resolvable_link_range)) = + (&link_data.resolvable_link, &link_data.resolvable_link_range) + else { + return Ok(()); + }; + let (Some(dest_res), Some(display_res)) = + (find_resolution(resolutions, &dest), find_resolution(resolutions, resolvable_link)) + else { + return Ok(()); + }; if dest_res == display_res { + let attr_span = item.attr_span(cx.tcx); let link_span = match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings) { Some((sp, from_expansion)) => { if from_expansion { - return None; + return Ok(()); } sp } - None => item.attr_span(cx.tcx), + None => attr_span, }; - let (explicit_span, false) = source_span_for_markdown_range( + let explicit_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_explicit_range(doc, link_range, open, close), &item.attrs.doc_strings, - )? - else { + ) { + Some((explicit_span, false)) => explicit_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksWithoutSuggestion { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (display_span, false) = source_span_for_markdown_range( + let display_span = match source_span_for_markdown_range( cx.tcx, doc, resolvable_link_range, &item.attrs.doc_strings, - )? - else { + ) { + Some((display_span, false)) => display_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksWithoutSuggestion { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; cx.tcx.emit_node_span_lint( @@ -247,7 +295,7 @@ fn check_inline_or_reference_unknown_redundancy( ); } - None + Ok(()) } /// FIXME(ChAoSUnItY): Too many arguments. @@ -260,7 +308,7 @@ fn check_reference_redundancy( link_range: Range, dest: &CowStr<'_>, link_data: LinkData, -) -> Option<()> { +) -> Result<(), RedundantExplicitLinksWithoutSuggestion> { struct RedundantExplicitLinkTarget { explicit_span: Span, display_span: Span, @@ -294,49 +342,83 @@ fn check_reference_redundancy( } } - let (resolvable_link, resolvable_link_range) = - (&link_data.resolvable_link?, &link_data.resolvable_link_range?); - let (dest_res, display_res) = - (find_resolution(resolutions, dest)?, find_resolution(resolutions, resolvable_link)?); + let (Some(resolvable_link), Some(resolvable_link_range)) = + (&link_data.resolvable_link, &link_data.resolvable_link_range) + else { + return Ok(()); + }; + let (Some(dest_res), Some(display_res)) = + (find_resolution(resolutions, dest), find_resolution(resolutions, resolvable_link)) + else { + return Ok(()); + }; if dest_res == display_res { + let attr_span = item.attr_span(cx.tcx); let link_span = match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings) { Some((sp, from_expansion)) => { if from_expansion { - return None; + // This `span` comes from macro expansion so skipping it. + return Ok(()); } sp } - None => item.attr_span(cx.tcx), + None => attr_span, }; - let (explicit_span, false) = source_span_for_markdown_range( + let explicit_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_explicit_range(doc, link_range.clone(), b'[', b']'), &item.attrs.doc_strings, - )? - else { + ) { + Some((explicit_span, false)) => explicit_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksWithoutSuggestion { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (display_span, false) = source_span_for_markdown_range( + let display_span = match source_span_for_markdown_range( cx.tcx, doc, resolvable_link_range, &item.attrs.doc_strings, - )? - else { + ) { + Some((display_span, false)) => display_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksWithoutSuggestion { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (def_span, _) = source_span_for_markdown_range( + let def_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_reference_def_range(doc, dest, link_range), &item.attrs.doc_strings, - )?; + ) { + Some((def_span, _)) => def_span, + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksWithoutSuggestion { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } + }; cx.tcx.emit_node_span_lint( crate::lint::REDUNDANT_EXPLICIT_LINKS, @@ -352,7 +434,7 @@ fn check_reference_redundancy( ); } - None + Ok(()) } fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option> { diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index c5816cb8b2d63..013fb32bdaf3c 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1242,7 +1242,8 @@ fn check_doc<'a, Events: Iterator, Range, Range tests/ui/doc/unbalanced_ticks.rs:6:5 + --> tests/ui/doc/unbalanced_ticks.rs:6:1 | -LL | /// This is a doc comment with `unbalanced_tick marks and several words that - | _____^ +LL | / /// This is a doc comment with `unbalanced_tick marks and several words that LL | | LL | | /// should be `encompassed_by` tick marks because they `contain_underscores`. LL | | /// Because of the initial `unbalanced_tick` pair, the error message is diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 7c4469afda282..70901f5b84c56 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -109,6 +109,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-pauthtest", "ignore-powerpc", "ignore-powerpc64", + "ignore-qnx", "ignore-remote", "ignore-riscv32", "ignore-riscv64", diff --git a/tests/codegen-llvm/thread-local.rs b/tests/codegen-llvm/thread-local.rs index 41df8c9be1b9d..8eb0443ebb9b5 100644 --- a/tests/codegen-llvm/thread-local.rs +++ b/tests/codegen-llvm/thread-local.rs @@ -5,6 +5,7 @@ //@ ignore-emscripten globals are used instead of thread locals //@ ignore-android does not use #[thread_local] //@ ignore-nto does not use #[thread_local] +//@ ignore-qnx does not use #[thread_local] #![crate_type = "lib"] diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs index d7efc201e7e39..53df3e9eb5a80 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs @@ -7,17 +7,17 @@ /// /// key +//~^^ ERROR: unclosed HTML tag `TH` /// +//~^^ ERROR: unopened HTML tag `TD` /// value +//~^^ ERROR: unclosed HTML tag `TH` /// +//~^^ ERROR: unopened HTML tag `TD` /// /// | |_____^ | @@ -18,7 +17,6 @@ error: unopened HTML tag `TD` | LL | /// | |_____^ diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.rs b/tests/rustdoc-ui/lints/invalid-html-tags.rs index 8003e5efdd582..f5700e5846e51 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.rs +++ b/tests/rustdoc-ui/lints/invalid-html-tags.rs @@ -164,8 +164,8 @@ pub fn r() {} /// >
/// > href="#broken" +//~^^ ERROR incomplete HTML tag `img` pub fn s() {} ///
diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.stderr b/tests/rustdoc-ui/lints/invalid-html-tags.stderr index b6ec22c247901..3256004ddb6ab 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.stderr +++ b/tests/rustdoc-ui/lints/invalid-html-tags.stderr @@ -123,7 +123,6 @@ error: incomplete HTML tag `img` | LL | /// > href="#broken" | |____________________^ diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs new file mode 100644 index 0000000000000..eebc6a0aa023c --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs @@ -0,0 +1,100 @@ +#![deny(rustdoc::redundant_explicit_links)] +use std::clone::Clone; + +/// [Clone]( +pub fn split_outer_inner() { + //! std::clone::Clone) +//~^^^ ERROR redundant_explicit_links +} + +/// [Clone](std::clone::Clone +pub fn split_outer_inner_b() { + //! ) +//~^^^ ERROR redundant_explicit_links +} + +/// [Clone]( +#[inline] +/// std::clone::Clone) +//~^^^ ERROR redundant_explicit_links +pub fn split_attr() { +} + +/// [Clone](std::clone::Clone +#[inline] +/// ) +//~^^^ ERROR redundant_explicit_links +pub fn split_attr_b() { +} + +/** [Clone]( */ #[inline] /** std::clone::Clone) */ +//~^ ERROR redundant_explicit_links +pub fn split_blockcomment_attr() { +} + +/** [Clone](std::clone::Clone */ #[inline] /** ) */ +//~^ ERROR redundant_explicit_links +pub fn split_blockcomment_attr_b() { +} + +/** [Clone]( */ +#[inline] +/** std::clone::Clone) */ +//~^^^ ERROR redundant_explicit_links +pub fn split_blockcomment_multiline_attr() { +} + +/** [Clone](std::clone::Clone */ +#[inline] +/** ) */ +//~^^^ ERROR redundant_explicit_links +pub fn split_blockcomment_multiline_attr_b() { +} + +/** [Clone]( */ #[inline] +/** std::clone::Clone) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_twoline_attr() { +} + +/** [Clone](std::clone::Clone */ #[inline] +/** ) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_twoline_attr_b() { +} + +/** [Clone]( */ +#[inline] /** std::clone::Clone) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_secondline_attr() { +} + +/** [Clone](std::clone::Clone */ +#[inline] /** ) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_secondline_attr_b() { +} + +/** [Clone](std::clone::Clone) */ #[inline] +//~^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] +pub fn split_blockcomment_singleline_attr() { +} + +/** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } +//~^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] + +/// [Clone]( +/// std::clone::Clone) +//~^^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] +pub fn not_split() { +} + +/// [Clone](std::clone::Clone +/// ) +//~^^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] +pub fn not_split_b() { +} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr new file mode 100644 index 0000000000000..bfab5b751eedf --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr @@ -0,0 +1,201 @@ +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:4:1 + | +LL | / /// [Clone]( +LL | | pub fn split_outer_inner() { +LL | | //! std::clone::Clone) + | |__________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +note: the lint level is defined here + --> $DIR/redundant_explicit_links_split.rs:1:9 + | +LL | #![deny(rustdoc::redundant_explicit_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:10:1 + | +LL | / /// [Clone](std::clone::Clone +LL | | pub fn split_outer_inner_b() { +LL | | //! ) + | |_________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:16:1 + | +LL | / /// [Clone]( +LL | | #[inline] +LL | | /// std::clone::Clone) + | |______________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:23:1 + | +LL | / /// [Clone](std::clone::Clone +LL | | #[inline] +LL | | /// ) + | |_____^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:30:1 + | +LL | /** [Clone]( */ #[inline] /** std::clone::Clone) */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:35:1 + | +LL | /** [Clone](std::clone::Clone */ #[inline] /** ) */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:40:1 + | +LL | / /** [Clone]( */ +LL | | #[inline] +LL | | /** std::clone::Clone) */ + | |_________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:47:1 + | +LL | / /** [Clone](std::clone::Clone */ +LL | | #[inline] +LL | | /** ) */ + | |________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:54:1 + | +LL | / /** [Clone]( */ #[inline] +LL | | /** std::clone::Clone) */ + | |_________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:60:1 + | +LL | / /** [Clone](std::clone::Clone */ #[inline] +LL | | /** ) */ + | |________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:66:1 + | +LL | / /** [Clone]( */ +LL | | #[inline] /** std::clone::Clone) */ + | |___________________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:72:1 + | +LL | / /** [Clone](std::clone::Clone */ +LL | | #[inline] /** ) */ + | |__________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:78:13 + | +LL | /** [Clone](std::clone::Clone) */ #[inline] + | ----- ^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /** [Clone](std::clone::Clone) */ #[inline] +LL + /** [Clone] */ #[inline] + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:84:13 + | +LL | /** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } + | ----- ^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } +LL + /** [Clone] */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:88:13 + | +LL | /// [Clone]( + | ______-----__^ + | | | + | | because label contains path that resolves to same destination +LL | | /// std::clone::Clone) + | |_____________________^ explicit target is redundant + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /// [Clone]( +LL - /// std::clone::Clone) +LL + /// [Clone] + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:95:13 + | +LL | /// [Clone](std::clone::Clone + | ______-----__^ + | | | + | | because label contains path that resolves to same destination +LL | | /// ) + | |____^ explicit target is redundant + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /// [Clone](std::clone::Clone +LL - /// ) +LL + /// [Clone] + | + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs index 6203be90590d3..94ba5a79aa725 100644 --- a/tests/ui/abi/stack-probes-lto.rs +++ b/tests/ui/abi/stack-probes-lto.rs @@ -8,7 +8,8 @@ //@ ignore-fuchsia no exception handler registered for segfault //@ compile-flags: -C lto //@ no-prefer-dynamic -//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX SDP 7.x +//@ ignore-qnx Crash analysis impossible at SIGSEGV in QNX SDP 8.0+ //@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index 4d0301411e0fd..be36eeefc31ea 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -5,7 +5,8 @@ //@[x64] only-x86_64 //@ needs-subprocess //@ ignore-fuchsia no exception handler registered for segfault -//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX SDP 7.x +//@ ignore-qnx Crash analysis impossible at SIGSEGV in QNX SDP 8.0+ //@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index b4f3570d9f2da..461b065d55ad3 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -6,6 +6,10 @@ LL | require_send(future); | = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` +help: consider adding an explicit type annotation to the closure's argument + | +LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { + | +++++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 @@ -16,6 +20,10 @@ LL | require_send(future); = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { + | +++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed b/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed new file mode 100644 index 0000000000000..e4a948eb9f7bd --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed @@ -0,0 +1,44 @@ +//@ run-rustfix +// When a closure is passed where a higher-ranked `FnOnce` is expected, but the closure +// parameter has no explicit type annotation, the compiler should suggest adding one. +// See . + +fn inner(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + match func(buf) { + Ok(n) => n, + Err(e) => e as usize, + } +} + +fn outer(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + let outer_closure = |buf: &mut [u8]| { + match func(buf) { + Ok(n) => { + println!("OK: {n}"); + Ok(n) + } + Err(e) => { + println!("ERR: {e}"); + Err(e) + } + } + }; + + inner(buf, outer_closure) + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough +} + +fn main() { + let mut x = [0u8; 16]; + let res = outer(&mut x, |buf| { + if buf.len() % 2 == 0 { Ok(buf.len()) } else { Err(buf.len() as isize) } + }); + println!("{res:?}"); +} diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs new file mode 100644 index 0000000000000..080874d8e236a --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs @@ -0,0 +1,44 @@ +//@ run-rustfix +// When a closure is passed where a higher-ranked `FnOnce` is expected, but the closure +// parameter has no explicit type annotation, the compiler should suggest adding one. +// See . + +fn inner(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + match func(buf) { + Ok(n) => n, + Err(e) => e as usize, + } +} + +fn outer(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + let outer_closure = |buf| { + match func(buf) { + Ok(n) => { + println!("OK: {n}"); + Ok(n) + } + Err(e) => { + println!("ERR: {e}"); + Err(e) + } + } + }; + + inner(buf, outer_closure) + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough +} + +fn main() { + let mut x = [0u8; 16]; + let res = outer(&mut x, |buf| { + if buf.len() % 2 == 0 { Ok(buf.len()) } else { Err(buf.len() as isize) } + }); + println!("{res:?}"); +} diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr new file mode 100644 index 0000000000000..51691c35f795b --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr @@ -0,0 +1,29 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 + | +LL | inner(buf, outer_closure) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let outer_closure = |buf: &mut [u8]| { + | +++++++++++ + +error: implementation of `FnOnce` is not general enough + --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 + | +LL | inner(buf, outer_closure) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let outer_closure = |buf: &mut [u8]| { + | +++++++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/command/command-setgroups.rs b/tests/ui/command/command-setgroups.rs index 047f06729af98..6e369c9b56c04 100644 --- a/tests/ui/command/command-setgroups.rs +++ b/tests/ui/command/command-setgroups.rs @@ -2,6 +2,7 @@ //@ only-unix (this is a unix-specific test) //@ ignore-musl - returns dummy result for _SC_NGROUPS_MAX //@ ignore-nto - does not have `/bin/id`, expects groups to be i32 (not u32) +//@ ignore-qnx - does not have `/bin/id`, expects groups to be i32 (not u32) //@ needs-subprocess #![feature(rustc_private)] diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index b2bb417a8f01b..3c6aab12bf137 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -6,6 +6,10 @@ LL | foo(bar, "string", |s| s.len() == 5); | = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | foo(bar, "string", |s: &&str| s.len() == 5); + | +++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 @@ -16,6 +20,10 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | foo(bar, "string", |s: &&str| s.len() == 5); + | +++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 @@ -25,6 +33,10 @@ LL | foo(baz, "string", |s| s.0.len() == 5); | = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); + | ++++++++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 @@ -35,6 +47,10 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); + | ++++++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 4b3d0e8ac5efc..db623761b268e 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -6,6 +6,10 @@ LL | thing(f); | = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` +help: consider adding explicit type annotations to the closure's arguments + | +LL | let f = | _: &u32 , y: &u32 , z: u32 | (); + | ++++++ +++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 @@ -16,6 +20,10 @@ LL | thing(f); = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding explicit type annotations to the closure's arguments + | +LL | let f = | _: &u32 , y: &u32 , z: u32 | (); + | ++++++ +++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -25,6 +33,10 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -34,6 +46,10 @@ LL | thing(f); | = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -44,6 +60,10 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -54,6 +74,10 @@ LL | thing(f); = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 78f6ce882dfab..2731d0972d2bc 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -24,6 +24,10 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | take_foo(|a: &i32| a); + | ++++++ error: implementation of `Fn` is not general enough --> $DIR/issue-79187-2.rs:8:5 @@ -33,6 +37,10 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | take_foo(|a: &i32| a); + | ++++++ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:11:5 diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 8adde8d6dfbf3..e08400481e470 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -6,6 +6,10 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = |_: &u32| (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 @@ -16,6 +20,10 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let f = |_: &u32| (); + | ++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/closure-mismatch.current.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr index 378fe83ea89bd..82e3e4b0f78f2 100644 --- a/tests/ui/mismatched_types/closure-mismatch.current.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -6,6 +6,10 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | baz(|_: &()| ()); + | +++++ error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:12:5 @@ -15,6 +19,10 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | baz(|_: &()| ()); + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:16:5 @@ -24,6 +32,10 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | baz(|x: &()| ()); + | +++++ error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:16:5 @@ -33,6 +45,10 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | baz(|x: &()| ()); + | +++++ error: aborting due to 4 previous errors diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index 629570b602ed6..45dd1557dd027 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -6,6 +6,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 @@ -16,6 +20,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: higher-ranked subtype error --> $DIR/ice-106874.rs:8:5 @@ -39,6 +47,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -48,6 +60,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -58,6 +74,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -68,6 +88,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -78,6 +102,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -88,6 +116,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: aborting due to 10 previous errors diff --git a/tests/ui/nll/issue-57843.stderr b/tests/ui/nll/issue-57843.stderr index eed511460cac7..386f952c0541d 100644 --- a/tests/ui/nll/issue-57843.stderr +++ b/tests/ui/nll/issue-57843.stderr @@ -6,6 +6,10 @@ LL | Foo(Box::new(|_| ())); | = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | Foo(Box::new(|_: &'a bool| ())); + | ++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index c2e91edd13872..d8922ef80e813 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -6,6 +6,10 @@ LL | accept(callback); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -16,6 +20,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -26,6 +34,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -36,6 +48,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: higher-ranked subtype error --> $DIR/missing-universe-cause-issue-114907.rs:33:5 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 804b3f00a2642..0734eba1496d7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -32,6 +32,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -41,6 +45,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 804b3f00a2642..0734eba1496d7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -32,6 +32,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -41,6 +45,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/process/process-spawn-failure.rs b/tests/ui/process/process-spawn-failure.rs index b3f0071670bc6..b0a88b53bf0a4 100644 --- a/tests/ui/process/process-spawn-failure.rs +++ b/tests/ui/process/process-spawn-failure.rs @@ -9,6 +9,7 @@ //@ ignore-vxworks no 'ps' //@ ignore-fuchsia no 'ps' //@ ignore-nto no 'ps' +//@ ignore-qnx no 'ps' //@ ignore-ios no 'ps' //@ ignore-tvos no 'ps' //@ ignore-watchos no 'ps' diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index 3e092728f2929..9b3878229417c 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -6,6 +6,7 @@ //@ needs-subprocess //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590) //@ ignore-nto no stack overflow handler used (no alternate stack available) +//@ ignore-qnx no stack overflow handler used (no alternate stack available) //@ ignore-ios stack overflow handlers aren't enabled //@ ignore-tvos stack overflow handlers aren't enabled //@ ignore-watchos stack overflow handlers aren't enabled diff --git a/tests/ui/runtime/signal-alternate-stack-cleanup.rs b/tests/ui/runtime/signal-alternate-stack-cleanup.rs index 8d52e9e26a29c..73bf741a73f1c 100644 --- a/tests/ui/runtime/signal-alternate-stack-cleanup.rs +++ b/tests/ui/runtime/signal-alternate-stack-cleanup.rs @@ -8,6 +8,7 @@ //@ ignore-sgx no libc //@ ignore-vxworks no SIGWINCH in user space //@ ignore-nto no SA_ONSTACK +//@ ignore-qnx no SA_ONSTACK #![allow(function_casts_as_integer)] #![feature(rustc_private)] diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index 88d9736a071de..93416a9bc2ac7 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -4,6 +4,7 @@ //@ ignore-emscripten globals are used instead of thread locals //@ ignore-android does not use #[thread_local] //@ ignore-nto does not use #[thread_local] +//@ ignore-qnx does not use #[thread_local] // Different number of duplicated diagnostics on different targets //@ compile-flags: -Zdeduplicate-diagnostics=yes diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index b8c58155e636d..4c50f2a43e270 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:26:44 + --> $DIR/missing-lifetime-specifier.rs:27:44 | LL | static a: RefCell>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,7 +11,7 @@ LL | static a: RefCell>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:30:44 + --> $DIR/missing-lifetime-specifier.rs:31:44 | LL | static b: RefCell>>> = RefCell::new(HashMap::new()); | ^ ^^^ expected 2 lifetime parameters @@ -25,7 +25,7 @@ LL | static b: RefCell $DIR/missing-lifetime-specifier.rs:34:47 + --> $DIR/missing-lifetime-specifier.rs:35:47 | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -37,7 +37,7 @@ LL | static c: RefCell>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); | ^ ^ expected 2 lifetime parameters @@ -51,7 +51,7 @@ LL | static d: RefCell $DIR/missing-lifetime-specifier.rs:47:44 + --> $DIR/missing-lifetime-specifier.rs:48:44 | LL | static f: RefCell>>>> = | ^ expected named lifetime parameter @@ -68,7 +68,7 @@ LL + static f: RefCell>>>> = | error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:44:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -76,7 +76,7 @@ LL | static e: RefCell>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:19:11 + --> $DIR/missing-lifetime-specifier.rs:20:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -86,7 +86,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:49 + --> $DIR/missing-lifetime-specifier.rs:48:49 | LL | static f: RefCell>>>> = | ^^^ ------- supplied 1 lifetime argument @@ -94,7 +94,7 @@ LL | static f: RefCell>>>> = | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:23:7 + --> $DIR/missing-lifetime-specifier.rs:24:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- diff --git a/tests/ui/traits/final/overriding-rpitit.rs b/tests/ui/traits/final/overriding-rpitit.rs new file mode 100644 index 0000000000000..b44b470175ce4 --- /dev/null +++ b/tests/ui/traits/final/overriding-rpitit.rs @@ -0,0 +1,18 @@ +#![feature(final_associated_functions)] + +// Regression test for https://github.com/rust-lang/rust/issues/158824. + +trait Item { + final fn bar() -> impl Clone { + todo!() + } +} + +struct Foo; + +impl Item for Foo { + fn bar() -> impl Clone {} + //~^ ERROR cannot override `bar` because it already has a `final` definition in the trait +} + +fn main() {} diff --git a/tests/ui/traits/final/overriding-rpitit.stderr b/tests/ui/traits/final/overriding-rpitit.stderr new file mode 100644 index 0000000000000..b865171472bab --- /dev/null +++ b/tests/ui/traits/final/overriding-rpitit.stderr @@ -0,0 +1,14 @@ +error: cannot override `bar` because it already has a `final` definition in the trait + --> $DIR/overriding-rpitit.rs:14:5 + | +LL | fn bar() -> impl Clone {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: `bar` is marked final here + --> $DIR/overriding-rpitit.rs:6:5 + | +LL | final fn bar() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +