From 4913ab8f779582dc9da099a148a4670ede0e15aa Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Tue, 20 Feb 2024 20:55:13 -0700
Subject: [PATCH 0001/1716] Stabilize `LazyCell` and `LazyLock` (`lazy_cell`)
---
.../rustc_const_eval/src/check_consts/ops.rs | 2 +-
compiler/rustc_data_structures/src/lib.rs | 1 -
compiler/rustc_error_messages/src/lib.rs | 1 -
compiler/rustc_feature/src/lib.rs | 1 -
compiler/rustc_hir_analysis/src/lib.rs | 1 -
compiler/rustc_interface/src/lib.rs | 1 -
compiler/rustc_lint_defs/src/builtin.rs | 10 ++---
compiler/rustc_session/src/lib.rs | 1 -
library/core/src/cell.rs | 2 +-
library/core/src/cell/lazy.rs | 20 ++++-----
library/core/tests/lib.rs | 1 -
library/std/src/lib.rs | 1 -
library/std/src/sync/lazy_lock.rs | 41 +++++++++++--------
library/std/src/sync/mod.rs | 2 +-
src/librustdoc/lib.rs | 1 -
src/tools/clippy/clippy_dev/src/lib.rs | 1 -
src/tools/clippy/src/driver.rs | 1 -
src/tools/clippy/tests/compile-test.rs | 1 -
src/tools/clippy/tests/dogfood.rs | 1 -
.../clippy/tests/lint_message_convention.rs | 1 -
src/tools/clippy/tests/workspace.rs | 2 -
tests/ui/borrowck/issue-64453.stderr | 2 +-
tests/ui/consts/issue-16538.stderr | 2 +-
tests/ui/consts/issue-32829-2.stderr | 4 +-
tests/ui/consts/mir_check_nonconst.stderr | 2 +-
tests/ui/issues/issue-25901.stderr | 2 +-
tests/ui/issues/issue-7364.stderr | 2 +-
tests/ui/lint/suspicious-double-ref-op.rs | 1 -
tests/ui/lint/suspicious-double-ref-op.stderr | 10 ++---
.../issue-35813-postfix-after-cast.stderr | 2 +-
.../nested-closure.rs | 2 +-
.../ui/static/static-mut-not-constant.stderr | 2 +-
.../static-vec-repeat-not-constant.stderr | 2 +-
.../statics/check-values-constraints.stderr | 16 ++++----
34 files changed, 60 insertions(+), 82 deletions(-)
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 8406e0f48762..90b622cae656 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -309,7 +309,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}
if let ConstContext::Static(_) = ccx.const_kind() {
- err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
+ err.note("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`");
}
err
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 85b5a3cdb7c3..9781aae22eb3 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -24,7 +24,6 @@
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
-#![feature(lazy_cell)]
#![feature(lint_reasons)]
#![feature(macro_metavar_expr)]
#![feature(map_try_insert)]
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 2a8f42220640..08388c5a58ed 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -1,6 +1,5 @@
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
-#![feature(lazy_cell)]
#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
#![allow(internal_features)]
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 36ef8fe7816f..9cbf836ec76f 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -14,7 +14,6 @@
#![allow(internal_features)]
#![feature(rustdoc_internals)]
#![doc(rust_logo)]
-#![feature(lazy_cell)]
mod accepted;
mod builtin_attrs;
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index d1e50e13894a..8fe81851f932 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -68,7 +68,6 @@ This API is completely unstable and subject to change.
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
-#![feature(lazy_cell)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index c1d460ddd086..8b1d9b706cac 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,5 +1,4 @@
#![feature(decl_macro)]
-#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(thread_spawn_unchecked)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 617fe99ef6a7..747b7292a199 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1316,10 +1316,8 @@ declare_lint! {
/// * If you are trying to perform a one-time initialization of a global:
/// * If the value can be computed at compile-time, consider using
/// const-compatible values (see [Constant Evaluation]).
- /// * For more complex single-initialization cases, consider using a
- /// third-party crate, such as [`lazy_static`] or [`once_cell`].
- /// * If you are using the [nightly channel], consider the new
- /// [`lazy`] module in the standard library.
+ /// * For more complex single-initialization cases, consider using
+ /// [`std::sync::LazyLock`].
/// * If you truly need a mutable global, consider using a [`static`],
/// which has a variety of options:
/// * Simple data types can be directly defined and mutated with an
@@ -1334,9 +1332,7 @@ declare_lint! {
/// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html
/// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
/// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics
- /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html
- /// [`lazy_static`]: https://crates.io/crates/lazy_static
- /// [`once_cell`]: https://crates.io/crates/once_cell
+ /// [`std::sync::LazyLock`]: https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html
/// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html
/// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
pub CONST_ITEM_MUTATION,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index ce866906e1e6..cb02fbdfee9e 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,5 +1,4 @@
#![feature(let_chains)]
-#![feature(lazy_cell)]
#![feature(option_get_or_insert_default)]
#![feature(rustc_attrs)]
#![feature(map_many_mut)]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 4b491ffdafa7..ac026de95da1 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -245,7 +245,7 @@ use crate::ptr::{self, NonNull};
mod lazy;
mod once;
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub use lazy::LazyCell;
#[stable(feature = "once_cell", since = "1.70.0")]
pub use once::OnceCell;
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index 1b213f6a2941..47eab6fd0163 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -18,8 +18,6 @@ enum State {
/// # Examples
///
/// ```
-/// #![feature(lazy_cell)]
-///
/// use std::cell::LazyCell;
///
/// let lazy: LazyCell = LazyCell::new(|| {
@@ -36,7 +34,7 @@ enum State {
/// // 92
/// // 92
/// ```
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub struct LazyCell T> {
state: UnsafeCell>,
}
@@ -47,8 +45,6 @@ impl T> LazyCell {
/// # Examples
///
/// ```
- /// #![feature(lazy_cell)]
- ///
/// use std::cell::LazyCell;
///
/// let hello = "Hello, World!".to_string();
@@ -58,7 +54,8 @@ impl T> LazyCell {
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// ```
#[inline]
- #[unstable(feature = "lazy_cell", issue = "109736")]
+ #[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub const fn new(f: F) -> LazyCell {
LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
}
@@ -70,7 +67,6 @@ impl T> LazyCell {
/// # Examples
///
/// ```
- /// #![feature(lazy_cell)]
/// #![feature(lazy_cell_consume)]
///
/// use std::cell::LazyCell;
@@ -99,8 +95,6 @@ impl T> LazyCell {
/// # Examples
///
/// ```
- /// #![feature(lazy_cell)]
- ///
/// use std::cell::LazyCell;
///
/// let lazy = LazyCell::new(|| 92);
@@ -109,7 +103,7 @@ impl T> LazyCell {
/// assert_eq!(&*lazy, &92);
/// ```
#[inline]
- #[unstable(feature = "lazy_cell", issue = "109736")]
+ #[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn force(this: &LazyCell) -> &T {
// SAFETY:
// This invalidates any mutable references to the data. The resulting
@@ -173,7 +167,7 @@ impl LazyCell {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl T> Deref for LazyCell {
type Target = T;
#[inline]
@@ -182,7 +176,7 @@ impl T> Deref for LazyCell {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl Default for LazyCell {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
@@ -191,7 +185,7 @@ impl Default for LazyCell {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Debug for LazyCell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("LazyCell");
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 797108a8425d..e6828f6cb4ea 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -96,7 +96,6 @@
#![feature(pointer_is_aligned_to)]
#![feature(portable_simd)]
#![feature(ptr_metadata)]
-#![feature(lazy_cell)]
#![feature(unsized_tuple_coercion)]
#![feature(const_option)]
#![feature(const_option_ext)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 4a18db3d5a3f..9d6576fa8411 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -395,7 +395,6 @@
#![feature(edition_panic)]
#![feature(format_args_nl)]
#![feature(get_many_mut)]
-#![feature(lazy_cell)]
#![feature(log_syntax)]
#![feature(test)]
#![feature(trace_macros)]
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 27b59cfc8c24..16d5dc30552f 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -31,8 +31,6 @@ union Data {
/// Initialize static variables with `LazyLock`.
///
/// ```
-/// #![feature(lazy_cell)]
-///
/// use std::collections::HashMap;
///
/// use std::sync::LazyLock;
@@ -61,8 +59,6 @@ union Data {
/// ```
/// Initialize fields with `LazyLock`.
/// ```
-/// #![feature(lazy_cell)]
-///
/// use std::sync::LazyLock;
///
/// #[derive(Debug)]
@@ -76,8 +72,7 @@ union Data {
/// println!("{}", *data.number);
/// }
/// ```
-
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub struct LazyLock T> {
once: Once,
data: UnsafeCell>,
@@ -85,8 +80,21 @@ pub struct LazyLock T> {
impl T> LazyLock {
/// Creates a new lazy value with the given initializing function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::LazyLock;
+ ///
+ /// let hello = "Hello, World!".to_string();
+ ///
+ /// let lazy = LazyLock::new(|| hello.to_uppercase());
+ ///
+ /// assert_eq!(&*lazy, "HELLO, WORLD!");
+ /// ```
#[inline]
- #[unstable(feature = "lazy_cell", issue = "109736")]
+ #[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub const fn new(f: F) -> LazyLock {
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
}
@@ -107,7 +115,6 @@ impl T> LazyLock {
/// # Examples
///
/// ```
- /// #![feature(lazy_cell)]
/// #![feature(lazy_cell_consume)]
///
/// use std::sync::LazyLock;
@@ -145,8 +152,6 @@ impl T> LazyLock {
/// # Examples
///
/// ```
- /// #![feature(lazy_cell)]
- ///
/// use std::sync::LazyLock;
///
/// let lazy = LazyLock::new(|| 92);
@@ -155,7 +160,7 @@ impl T> LazyLock {
/// assert_eq!(&*lazy, &92);
/// ```
#[inline]
- #[unstable(feature = "lazy_cell", issue = "109736")]
+ #[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub fn force(this: &LazyLock) -> &T {
this.once.call_once(|| {
// SAFETY: `call_once` only runs this closure once, ever.
@@ -191,7 +196,7 @@ impl LazyLock {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl Drop for LazyLock {
fn drop(&mut self) {
match self.once.state() {
@@ -204,7 +209,7 @@ impl Drop for LazyLock {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl T> Deref for LazyLock {
type Target = T;
@@ -219,7 +224,7 @@ impl T> Deref for LazyLock {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl Default for LazyLock {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
@@ -228,7 +233,7 @@ impl Default for LazyLock {
}
}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Debug for LazyLock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("LazyLock");
@@ -242,13 +247,13 @@ impl fmt::Debug for LazyLock {
// We never create a `&F` from a `&LazyLock` so it is fine
// to not impl `Sync` for `F`.
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
unsafe impl Sync for LazyLock {}
// auto-derived `Send` impl is OK.
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl RefUnwindSafe for LazyLock {}
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
impl UnwindSafe for LazyLock {}
#[cfg(test)]
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index e8c35bd48a70..fb7d601b0947 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -179,7 +179,7 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
-#[unstable(feature = "lazy_cell", issue = "109736")]
+#[stable(feature = "lazy_cell", since = "CURRENT_RUSTC_VERSION")]
pub use self::lazy_lock::LazyLock;
#[stable(feature = "once_cell", since = "1.70.0")]
pub use self::once_lock::OnceLock;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0650afb90c7e..55346c768b66 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -8,7 +8,6 @@
#![feature(if_let_guard)]
#![feature(impl_trait_in_assoc_type)]
#![feature(iter_intersperse)]
-#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(round_char_boundary)]
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 385191e0361b..3aa43dbe23ed 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(rustc_private)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 9e42abbc9aa9..f79da26964f3 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -2,7 +2,6 @@
#![allow(rustc::untranslatable_diagnostic)]
#![feature(rustc_private)]
#![feature(let_chains)]
-#![feature(lazy_cell)]
#![feature(lint_reasons)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index b06a11702ec8..333a2ab58575 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![feature(is_sorted)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 3f16c180ea78..36a7a651c4d2 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -3,7 +3,6 @@
//!
//! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
-#![feature(lazy_cell)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index 98019c755276..6ce7e44474d8 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/src/tools/clippy/tests/workspace.rs b/src/tools/clippy/tests/workspace.rs
index 699ab2be199a..19ccc7ae9607 100644
--- a/src/tools/clippy/tests/workspace.rs
+++ b/src/tools/clippy/tests/workspace.rs
@@ -1,5 +1,3 @@
-#![feature(lazy_cell)]
-
use std::path::PathBuf;
use std::process::Command;
use test_utils::{CARGO_CLIPPY_PATH, IS_RUSTC_TEST_SUITE};
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index 0e4a8d42f6e8..e671817633be 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -14,7 +14,7 @@ LL | static settings_dir: String = format!("");
| ^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0507]: cannot move out of static item `settings_dir`
diff --git a/tests/ui/consts/issue-16538.stderr b/tests/ui/consts/issue-16538.stderr
index 3981b4ada491..c4f5364b4d78 100644
--- a/tests/ui/consts/issue-16538.stderr
+++ b/tests/ui/consts/issue-16538.stderr
@@ -5,7 +5,7 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> $DIR/issue-16538.rs:11:22
diff --git a/tests/ui/consts/issue-32829-2.stderr b/tests/ui/consts/issue-32829-2.stderr
index 0fec3581873e..bd0b8c15b558 100644
--- a/tests/ui/consts/issue-32829-2.stderr
+++ b/tests/ui/consts/issue-32829-2.stderr
@@ -13,7 +13,7 @@ LL | invalid();
| ^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error[E0015]: cannot call non-const fn `invalid` in statics
--> $DIR/issue-32829-2.rs:54:9
@@ -22,7 +22,7 @@ LL | invalid();
| ^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/mir_check_nonconst.stderr b/tests/ui/consts/mir_check_nonconst.stderr
index ea6a8b8ee4a5..95d64622ad7a 100644
--- a/tests/ui/consts/mir_check_nonconst.stderr
+++ b/tests/ui/consts/mir_check_nonconst.stderr
@@ -5,7 +5,7 @@ LL | static foo: Foo = bar();
| ^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr
index 5c19abffa029..3fedfd964170 100644
--- a/tests/ui/issues/issue-25901.stderr
+++ b/tests/ui/issues/issue-25901.stderr
@@ -16,7 +16,7 @@ note: impl defined here, but it is not `const`
LL | impl Deref for A {
| ^^^^^^^^^^^^^^^^
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
LL + #![feature(const_trait_impl)]
diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr
index 3bf59a6d7114..d5b6dde1f10e 100644
--- a/tests/ui/issues/issue-7364.stderr
+++ b/tests/ui/issues/issue-7364.stderr
@@ -18,7 +18,7 @@ LL | static boxed: Box> = Box::new(RefCell::new(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error: aborting due to 2 previous errors
diff --git a/tests/ui/lint/suspicious-double-ref-op.rs b/tests/ui/lint/suspicious-double-ref-op.rs
index bc8c23c7b895..5aeb81dbd65a 100644
--- a/tests/ui/lint/suspicious-double-ref-op.rs
+++ b/tests/ui/lint/suspicious-double-ref-op.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![deny(suspicious_double_ref_op, noop_method_call)]
use std::borrow::Borrow;
diff --git a/tests/ui/lint/suspicious-double-ref-op.stderr b/tests/ui/lint/suspicious-double-ref-op.stderr
index f5a71d40fc13..c956843c5078 100644
--- a/tests/ui/lint/suspicious-double-ref-op.stderr
+++ b/tests/ui/lint/suspicious-double-ref-op.stderr
@@ -1,29 +1,29 @@
error: using `.clone()` on a double reference, which returns `&Vec` instead of cloning the inner type
- --> $DIR/suspicious-double-ref-op.rs:15:23
+ --> $DIR/suspicious-double-ref-op.rs:14:23
|
LL | let z: &Vec<_> = y.clone();
| ^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/suspicious-double-ref-op.rs:2:9
+ --> $DIR/suspicious-double-ref-op.rs:1:9
|
LL | #![deny(suspicious_double_ref_op, noop_method_call)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: using `.clone()` on a double reference, which returns `&CloneType` instead of cloning the inner type
- --> $DIR/suspicious-double-ref-op.rs:33:63
+ --> $DIR/suspicious-double-ref-op.rs:32:63
|
LL | let clone_type_ref_clone: &CloneType = clone_type_ref.clone();
| ^^^^^^^^
error: using `.deref()` on a double reference, which returns `&PlainType` instead of dereferencing the inner type
- --> $DIR/suspicious-double-ref-op.rs:37:63
+ --> $DIR/suspicious-double-ref-op.rs:36:63
|
LL | let non_deref_type_deref: &PlainType = non_deref_type.deref();
| ^^^^^^^^
error: using `.clone()` on a double reference, which returns `&str` instead of cloning the inner type
- --> $DIR/suspicious-double-ref-op.rs:41:44
+ --> $DIR/suspicious-double-ref-op.rs:40:44
|
LL | let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // could use `*x` instead
| ^^^^^^^^
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 7b896ce14266..66b57c772d54 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -352,7 +352,7 @@ LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
| ^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
LL + #![feature(const_trait_impl)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs
index d43fabcedec5..7bd372c16952 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#![feature(const_trait_impl, lazy_cell)]
+#![feature(const_trait_impl)]
use std::sync::LazyLock;
diff --git a/tests/ui/static/static-mut-not-constant.stderr b/tests/ui/static/static-mut-not-constant.stderr
index d125bec59435..46dc175cb298 100644
--- a/tests/ui/static/static-mut-not-constant.stderr
+++ b/tests/ui/static/static-mut-not-constant.stderr
@@ -5,7 +5,7 @@ LL | static mut a: Box = Box::new(3);
| ^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error: aborting due to 1 previous error
diff --git a/tests/ui/static/static-vec-repeat-not-constant.stderr b/tests/ui/static/static-vec-repeat-not-constant.stderr
index db0c7eb8d35f..a3b930323d5b 100644
--- a/tests/ui/static/static-vec-repeat-not-constant.stderr
+++ b/tests/ui/static/static-vec-repeat-not-constant.stderr
@@ -5,7 +5,7 @@ LL | static a: [isize; 2] = [foo(); 2];
| ^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
error: aborting due to 1 previous error
diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
index 45a699f575fb..24763c175fc8 100644
--- a/tests/ui/statics/check-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -26,7 +26,7 @@ LL | static STATIC11: Vec = vec![MyOwned];
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0015]: cannot call non-const fn `::to_string` in statics
@@ -36,7 +36,7 @@ LL | field2: SafeEnum::Variant4("str".to_string()),
| ^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
LL + #![feature(const_trait_impl)]
@@ -57,7 +57,7 @@ LL | vec![MyOwned],
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0010]: allocations are not allowed in statics
@@ -75,7 +75,7 @@ LL | vec![MyOwned],
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0010]: allocations are not allowed in statics
@@ -93,7 +93,7 @@ LL | &vec![MyOwned],
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0010]: allocations are not allowed in statics
@@ -111,7 +111,7 @@ LL | &vec![MyOwned],
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0010]: allocations are not allowed in statics
@@ -129,7 +129,7 @@ LL | static STATIC19: Vec = vec![3];
| ^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0010]: allocations are not allowed in statics
@@ -147,7 +147,7 @@ LL | static x: Vec = vec![3];
| ^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
- = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
+ = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0507]: cannot move out of static item `x`
From 007c61732677fcd388f9f7887578724d1003f915 Mon Sep 17 00:00:00 2001
From: Jubilee Young
Date: Fri, 24 May 2024 01:33:55 -0700
Subject: [PATCH 0002/1716] clippy: unnest check_consts
---
clippy_utils/src/qualify_min_const_fn.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 8ee7d87acb3e..81e94725a70c 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -6,7 +6,7 @@
use clippy_config::msrvs::{self, Msrv};
use hir::LangItem;
use rustc_attr::StableSince;
-use rustc_const_eval::transform::check_consts::ConstCx;
+use rustc_const_eval::check_consts::ConstCx;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
From a456300af569750232afc0e98da28c4786fce19b Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Tue, 20 Feb 2024 20:55:13 -0700
Subject: [PATCH 0003/1716] Stabilize `LazyCell` and `LazyLock` (`lazy_cell`)
---
clippy_dev/src/lib.rs | 1 -
src/driver.rs | 1 -
tests/compile-test.rs | 1 -
tests/dogfood.rs | 1 -
tests/lint_message_convention.rs | 1 -
tests/workspace.rs | 2 --
6 files changed, 7 deletions(-)
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index 385191e0361b..3aa43dbe23ed 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(rustc_private)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
diff --git a/src/driver.rs b/src/driver.rs
index 9e42abbc9aa9..f79da26964f3 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -2,7 +2,6 @@
#![allow(rustc::untranslatable_diagnostic)]
#![feature(rustc_private)]
#![feature(let_chains)]
-#![feature(lazy_cell)]
#![feature(lint_reasons)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index b06a11702ec8..333a2ab58575 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![feature(is_sorted)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/tests/dogfood.rs b/tests/dogfood.rs
index 3f16c180ea78..36a7a651c4d2 100644
--- a/tests/dogfood.rs
+++ b/tests/dogfood.rs
@@ -3,7 +3,6 @@
//!
//! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
-#![feature(lazy_cell)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs
index 98019c755276..6ce7e44474d8 100644
--- a/tests/lint_message_convention.rs
+++ b/tests/lint_message_convention.rs
@@ -1,4 +1,3 @@
-#![feature(lazy_cell)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/tests/workspace.rs b/tests/workspace.rs
index 699ab2be199a..19ccc7ae9607 100644
--- a/tests/workspace.rs
+++ b/tests/workspace.rs
@@ -1,5 +1,3 @@
-#![feature(lazy_cell)]
-
use std::path::PathBuf;
use std::process::Command;
use test_utils::{CARGO_CLIPPY_PATH, IS_RUSTC_TEST_SUITE};
From 214c49837a56c402ab28f7dd5eff08c7ae709c09 Mon Sep 17 00:00:00 2001
From: Tobias Bucher
Date: Wed, 6 Mar 2024 12:42:32 +0100
Subject: [PATCH 0004/1716] Less syscalls for the `copy_file_range` probe
If it's obvious from the actual syscall results themselves that the
syscall is supported or unsupported, don't do an extra syscall with an
invalid file descriptor.
CC #122052
---
library/std/src/sys/pal/unix/kernel_copy.rs | 71 ++++++++++++++-------
1 file changed, 48 insertions(+), 23 deletions(-)
diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs
index 18acd5ecccd5..60f4e55755d7 100644
--- a/library/std/src/sys/pal/unix/kernel_copy.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy.rs
@@ -560,6 +560,12 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
// We store the availability in a global to avoid unnecessary syscalls
static HAS_COPY_FILE_RANGE: AtomicU8 = AtomicU8::new(NOT_PROBED);
+ let mut have_probed = match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) {
+ NOT_PROBED => false,
+ UNAVAILABLE => return CopyResult::Fallback(0),
+ _ => true,
+ };
+
syscall! {
fn copy_file_range(
fd_in: libc::c_int,
@@ -571,26 +577,6 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
) -> libc::ssize_t
}
- match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) {
- NOT_PROBED => {
- // EPERM can indicate seccomp filters or an immutable file.
- // To distinguish these cases we probe with invalid file descriptors which should result in EBADF if the syscall is supported
- // and some other error (ENOSYS or EPERM) if it's not available
- let result = unsafe {
- cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0))
- };
-
- if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF))) {
- HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
- } else {
- HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
- return CopyResult::Fallback(0);
- }
- }
- UNAVAILABLE => return CopyResult::Fallback(0),
- _ => {}
- };
-
let mut written = 0u64;
while written < max_len {
let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64);
@@ -604,6 +590,11 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
cvt(copy_file_range(reader, ptr::null_mut(), writer, ptr::null_mut(), bytes_to_copy, 0))
};
+ if !have_probed && copy_result.is_ok() {
+ have_probed = true;
+ HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
+ }
+
match copy_result {
Ok(0) if written == 0 => {
// fallback to work around several kernel bugs where copy_file_range will fail to
@@ -616,10 +607,44 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
Ok(0) => return CopyResult::Ended(written), // reached EOF
Ok(ret) => written += ret as u64,
Err(err) => {
- return match err.raw_os_error() {
+ let raw_os_error = match err.raw_os_error() {
+ Some(raw) => raw,
+ _ => return CopyResult::Error(err, written),
+ };
+ return match raw_os_error {
// when file offset + max_length > u64::MAX
- Some(EOVERFLOW) => CopyResult::Fallback(written),
- Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) if written == 0 => {
+ EOVERFLOW => CopyResult::Fallback(written),
+ ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF if written == 0 => {
+ if !have_probed {
+ if raw_os_error == ENOSYS {
+ HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
+ } else {
+ // EPERM can indicate seccomp filters or an
+ // immutable file. To distinguish these cases
+ // we probe with invalid file descriptors which
+ // should result in EBADF if the syscall is
+ // supported and some other error (ENOSYS or
+ // EPERM) if it's not available.
+ let result = unsafe {
+ cvt(copy_file_range(
+ INVALID_FD,
+ ptr::null_mut(),
+ INVALID_FD,
+ ptr::null_mut(),
+ 1,
+ 0,
+ ))
+ };
+
+ if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF)))
+ {
+ HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
+ } else {
+ HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
+ }
+ }
+ }
+
// Try fallback io::copy if either:
// - Kernel version is < 4.5 (ENOSYS¹)
// - Files are mounted on different fs (EXDEV)
From 5073475b0e5477c3d02c219a4c2e7075891240a7 Mon Sep 17 00:00:00 2001
From: Tobias Bucher
Date: Wed, 6 Mar 2024 14:37:25 +0100
Subject: [PATCH 0005/1716] Be stricter with `copy_file_range` probe results
---
library/std/src/sys/pal/unix/kernel_copy.rs | 68 +++++++++++----------
1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs
index 60f4e55755d7..1db86bdb180f 100644
--- a/library/std/src/sys/pal/unix/kernel_copy.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy.rs
@@ -607,42 +607,44 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
Ok(0) => return CopyResult::Ended(written), // reached EOF
Ok(ret) => written += ret as u64,
Err(err) => {
- let raw_os_error = match err.raw_os_error() {
- Some(raw) => raw,
- _ => return CopyResult::Error(err, written),
- };
- return match raw_os_error {
+ return match err.raw_os_error() {
// when file offset + max_length > u64::MAX
- EOVERFLOW => CopyResult::Fallback(written),
- ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF if written == 0 => {
+ Some(EOVERFLOW) => CopyResult::Fallback(written),
+ Some(raw_os_error @ (ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF))
+ if written == 0 =>
+ {
if !have_probed {
- if raw_os_error == ENOSYS {
- HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
- } else {
- // EPERM can indicate seccomp filters or an
- // immutable file. To distinguish these cases
- // we probe with invalid file descriptors which
- // should result in EBADF if the syscall is
- // supported and some other error (ENOSYS or
- // EPERM) if it's not available.
- let result = unsafe {
- cvt(copy_file_range(
- INVALID_FD,
- ptr::null_mut(),
- INVALID_FD,
- ptr::null_mut(),
- 1,
- 0,
- ))
- };
-
- if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF)))
- {
- HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
- } else {
- HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
+ let available = match raw_os_error {
+ EPERM => {
+ // EPERM can indicate seccomp filters or an
+ // immutable file. To distinguish these
+ // cases we probe with invalid file
+ // descriptors which should result in EBADF
+ // if the syscall is supported and EPERM or
+ // ENOSYS if it's not available.
+ match unsafe {
+ cvt(copy_file_range(
+ INVALID_FD,
+ ptr::null_mut(),
+ INVALID_FD,
+ ptr::null_mut(),
+ 1,
+ 0,
+ ))
+ .map_err(|e| e.raw_os_error())
+ } {
+ Err(Some(EPERM | ENOSYS)) => UNAVAILABLE,
+ Err(Some(EBADF)) => AVAILABLE,
+ Ok(_) => panic!("unexpected copy_file_range probe success"),
+ // Treat other errors as the syscall
+ // being unavailable.
+ Err(_) => UNAVAILABLE,
+ }
}
- }
+ ENOSYS => UNAVAILABLE,
+ _ => AVAILABLE,
+ };
+ HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed);
}
// Try fallback io::copy if either:
From 8e91a51cd81de5cf686d21db891634fecdc250c0 Mon Sep 17 00:00:00 2001
From: Matthias Geier
Date: Tue, 2 Apr 2024 18:54:24 +0200
Subject: [PATCH 0006/1716] DOC: Add FFI example for slice::from_raw_parts()
---
library/core/src/slice/raw.rs | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 29a12f106c5e..d001688d79d8 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -83,6 +83,27 @@ use crate::ub_checks;
/// }
/// ```
///
+/// ### FFI: Handling null pointers
+///
+/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null.
+/// When accepting such pointers, they have to be checked for null-ness to avoid undefined
+/// behavior.
+///
+/// ```
+/// use std::slice;
+///
+/// unsafe extern "C" fn handle_slice(ptr: *const f32, len: usize) {
+/// let data = if ptr.is_null() {
+/// // `len` is assumed to be 0.
+/// &[]
+/// } else {
+/// unsafe { slice::from_raw_parts(ptr, len) }
+/// };
+/// dbg!(data);
+/// // ...
+/// }
+/// ```
+///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
From a7238b9952ebc547db395af98e7dcec1d7794b02 Mon Sep 17 00:00:00 2001
From: Trevor Gross
Date: Tue, 9 Apr 2024 23:20:32 -0400
Subject: [PATCH 0007/1716] Update documentation related to the recent cmd.exe
fix
Fix some grammar nits, change `bat` (extension) -> `batch` (file), and
make line wrapping more consistent.
---
library/std/src/os/windows/process.rs | 49 +++++++++++++++++----------
library/std/src/process.rs | 48 ++++++++++++++------------
2 files changed, 59 insertions(+), 38 deletions(-)
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 15ab22501223..9cca27fa5dd5 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -199,14 +199,14 @@ pub trait CommandExt: Sealed {
/// Append literal text to the command line without any quoting or escaping.
///
- /// This is useful for passing arguments to applications which doesn't follow
+ /// This is useful for passing arguments to applications that don't follow
/// the standard C run-time escaping rules, such as `cmd.exe /c`.
///
- /// # Bat files
+ /// # Batch files
///
- /// Note the `cmd /c` command line has slightly different escaping rules then bat files
+ /// Note the `cmd /c` command line has slightly different escaping rules than batch files
/// themselves. If possible, it may be better to write complex arguments to a temporary
- /// .bat file, with appropriate escaping, and simply run that using:
+ /// `.bat` file, with appropriate escaping, and simply run that using:
///
/// ```no_run
/// # use std::process::Command;
@@ -217,7 +217,7 @@ pub trait CommandExt: Sealed {
///
/// # Example
///
- /// Run a bat script using both trusted and untrusted arguments.
+ /// Run a batch script using both trusted and untrusted arguments.
///
/// ```no_run
/// #[cfg(windows)]
@@ -241,9 +241,10 @@ pub trait CommandExt: Sealed {
/// if !user_name.chars().all(|c| c.is_alphanumeric()) {
/// return Err(Error::new(ErrorKind::InvalidInput, "invalid user name"));
/// }
- /// // now we've checked the user name, let's add that too.
- /// cmd_args.push(' ');
- /// cmd_args.push_str(&format!("--user {user_name}"));
+ ///
+ /// // now we have validated the user name, let's add that too.
+ /// cmd_args.push_str(" --user ");
+ /// cmd_args.push_str(user_name);
///
/// // call cmd.exe and return the output
/// Command::new("cmd.exe")
@@ -287,25 +288,37 @@ pub trait CommandExt: Sealed {
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
- /// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
+ /// Set a raw attribute on the command, providing extended configuration options for Windows
+ /// processes.
///
- /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
- /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
+ /// This method allows you to specify custom attributes for a child process on Windows systems
+ /// using raw attribute values. Raw attributes provide extended configurability for process
+ /// creation, but their usage can be complex and potentially unsafe.
///
- /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
- /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
+ /// The `attribute` parameter specifies the raw attribute to be set, while the `value`
+ /// parameter holds the value associated with that attribute. Please refer to the
+ /// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information
+ /// about available attributes and their meanings.
+ ///
+ /// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/
+ /// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
///
/// # Note
///
/// The maximum number of raw attributes is the value of [`u32::MAX`].
- /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
+ /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error`
+ /// indicating that the maximum number of attributes has been exceeded.
+ ///
/// # Safety
///
- /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
+ /// The usage of raw attributes is potentially unsafe and should be done with caution.
+ /// Incorrect attribute values or improper configuration can lead to unexpected behavior or
+ /// errors.
///
/// # Example
///
- /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
+ /// The following example demonstrates how to create a child process with a specific parent
+ /// process ID using a raw attribute.
///
/// ```rust
/// #![feature(windows_process_extensions_raw_attribute)]
@@ -339,7 +352,9 @@ pub trait CommandExt: Sealed {
///
/// # Safety Note
///
- /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
+ /// Remember that improper use of raw attributes can lead to undefined behavior or security
+ /// vulnerabilities. Always consult the documentation and ensure proper attribute values are
+ /// used.
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
unsafe fn raw_attribute(
&mut self,
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 69cc61b30efe..ea72a87dd25c 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -90,8 +90,8 @@
//!
//! # Windows argument splitting
//!
-//! On Unix systems arguments are passed to a new process as an array of strings
-//! but on Windows arguments are passed as a single commandline string and it's
+//! On Unix systems arguments are passed to a new process as an array of strings,
+//! but on Windows arguments are passed as a single commandline string and it is
//! up to the child process to parse it into an array. Therefore the parent and
//! child processes must agree on how the commandline string is encoded.
//!
@@ -107,26 +107,26 @@
//! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping
//! rules used by [`arg`] so should be used with due caution.
//!
-//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially
+//! `cmd.exe` and `.bat` files use non-standard argument parsing and are especially
//! vulnerable to malicious input as they may be used to run arbitrary shell
//! commands. Untrusted arguments should be restricted as much as possible.
//! For examples on handling this see [`raw_arg`].
//!
-//! ### Bat file special handling
+//! ### Batch file special handling
//!
//! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to
-//! spawn new processes. An undocumented feature of this function is that,
+//! spawn new processes. An undocumented feature of this function is that
//! when given a `.bat` file as the application to run, it will automatically
-//! convert that into running `cmd.exe /c` with the bat file as the next argument.
+//! convert that into running `cmd.exe /c` with the batch file as the next argument.
//!
//! For historical reasons Rust currently preserves this behaviour when using
//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
//! Due to the complexity of `cmd.exe` argument handling, it might not be
-//! possible to safely escape some special chars, and using them will result
+//! possible to safely escape some special characters, and using them will result
//! in an error being returned at process spawn. The set of unescapeable
-//! special chars might change between releases.
+//! special characters might change between releases.
//!
-//! Also note that running `.bat` scripts in this way may be removed in the
+//! Also note that running batch scripts in this way may be removed in the
//! future and so should not be relied upon.
//!
//! [`spawn`]: Command::spawn
@@ -655,16 +655,19 @@ impl Command {
///
/// Note that the argument is not passed through a shell, but given
/// literally to the program. This means that shell syntax like quotes,
- /// escaped characters, word splitting, glob patterns, variable substitution, etc.
- /// have no effect.
+ /// escaped characters, word splitting, glob patterns, variable substitution,
+ /// etc. have no effect.
///
///
///
- /// On Windows use caution with untrusted inputs. Most applications use the
- /// standard convention for decoding arguments passed to them. These are safe to use with `arg`.
- /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
- /// and are therefore vulnerable to malicious input.
- /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+ /// On Windows, use caution with untrusted inputs. Most applications use the
+ /// standard convention for decoding arguments passed to them. These are safe to
+ /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+ /// use a non-standard way of decoding arguments. They are therefore vulnerable
+ /// to malicious input.
+ ///
+ /// In the case of `cmd.exe` this is especially important because a malicious
+ /// argument can potentially run arbitrary shell commands.
///
/// See [Windows argument splitting][windows-args] for more details
/// or [`raw_arg`] for manually implementing non-standard argument encoding.
@@ -706,11 +709,14 @@ impl Command {
///
///
///
- /// On Windows use caution with untrusted inputs. Most applications use the
- /// standard convention for decoding arguments passed to them. These are safe to use with `args`.
- /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
- /// and are therefore vulnerable to malicious input.
- /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+ /// On Windows, use caution with untrusted inputs. Most applications use the
+ /// standard convention for decoding arguments passed to them. These are safe to
+ /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+ /// use a non-standard way of decoding arguments. They are therefore vulnerable
+ /// to malicious input.
+ ///
+ /// In the case of `cmd.exe` this is especially important because a malicious
+ /// argument can potentially run arbitrary shell commands.
///
/// See [Windows argument splitting][windows-args] for more details
/// or [`raw_arg`] for manually implementing non-standard argument encoding.
From cf0b55eb6232491a7c29ac0f47564b6ee7adb13e Mon Sep 17 00:00:00 2001
From: Alex Macleod
Date: Tue, 11 Apr 2023 19:47:44 +0000
Subject: [PATCH 0008/1716] Add `needless_maybe_sized` lint
---
CHANGELOG.md | 1 +
clippy_lints/src/declared_lints.rs | 1 +
clippy_lints/src/lib.rs | 2 +
clippy_lints/src/needless_maybe_sized.rs | 164 ++++++++
.../ui-toml/type_repetition_in_bounds/main.rs | 1 +
.../type_repetition_in_bounds/main.stderr | 2 +-
tests/ui/auxiliary/proc_macros.rs | 6 +-
tests/ui/needless_maybe_sized.fixed | 116 ++++++
tests/ui/needless_maybe_sized.rs | 119 ++++++
tests/ui/needless_maybe_sized.stderr | 353 ++++++++++++++++++
tests/ui/type_repetition_in_bounds.rs | 6 +-
tests/ui/type_repetition_in_bounds.stderr | 10 +-
12 files changed, 771 insertions(+), 10 deletions(-)
create mode 100644 clippy_lints/src/needless_maybe_sized.rs
create mode 100644 tests/ui/needless_maybe_sized.fixed
create mode 100644 tests/ui/needless_maybe_sized.rs
create mode 100644 tests/ui/needless_maybe_sized.stderr
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd3a04e34ae3..aaa53d8a6cb8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5523,6 +5523,7 @@ Released 2018-09-13
[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
[`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match
+[`needless_maybe_sized`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_maybe_sized
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 5ff7d8e51343..dd16e13e7add 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -527,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
crate::needless_if::NEEDLESS_IF_INFO,
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
+ crate::needless_maybe_sized::NEEDLESS_MAYBE_SIZED_INFO,
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO,
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index e2aac58bf979..bfddbffe9b23 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -254,6 +254,7 @@ mod needless_else;
mod needless_for_each;
mod needless_if;
mod needless_late_init;
+mod needless_maybe_sized;
mod needless_parens_on_range_literals;
mod needless_pass_by_ref_mut;
mod needless_pass_by_value;
@@ -1032,6 +1033,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead));
store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
+ store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs
new file mode 100644
index 000000000000..06ae1723a03d
--- /dev/null
+++ b/clippy_lints/src/needless_maybe_sized.rs
@@ -0,0 +1,164 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::def_id::{DefId, DefIdMap};
+use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{ClauseKind, PredicatePolarity};
+use rustc_session::declare_lint_pass;
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints `?Sized` bounds applied to type parameters that cannot be unsized
+ ///
+ /// ### Why is this bad?
+ /// The `?Sized` bound is misleading because it cannot be satisfied by an
+ /// unsized type
+ ///
+ /// ### Example
+ /// ```rust
+ /// // `T` cannot be unsized because `Clone` requires it to be `Sized`
+ /// fn f(t: &T) {}
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn f(t: &T) {}
+ ///
+ /// // or choose alternative bounds for `T` so that it can be unsized
+ /// ```
+ #[clippy::version = "1.79.0"]
+ pub NEEDLESS_MAYBE_SIZED,
+ suspicious,
+ "a `?Sized` bound that is unusable due to a `Sized` requirement"
+}
+declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]);
+
+#[allow(clippy::struct_field_names)]
+struct Bound<'tcx> {
+ /// The [`DefId`] of the type parameter the bound refers to
+ param: DefId,
+ ident: Ident,
+
+ trait_bound: &'tcx PolyTraitRef<'tcx>,
+ modifier: TraitBoundModifier,
+
+ predicate_pos: usize,
+ bound_pos: usize,
+}
+
+/// Finds all of the [`Bound`]s that refer to a type parameter and are not from a macro expansion
+fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator> {
+ generics
+ .predicates
+ .iter()
+ .enumerate()
+ .filter_map(|(predicate_pos, predicate)| {
+ let WherePredicate::BoundPredicate(bound_predicate) = predicate else {
+ return None;
+ };
+
+ let (param, ident) = bound_predicate.bounded_ty.as_generic_param()?;
+
+ Some(
+ bound_predicate
+ .bounds
+ .iter()
+ .enumerate()
+ .filter_map(move |(bound_pos, bound)| match bound {
+ &GenericBound::Trait(ref trait_bound, modifier) => Some(Bound {
+ param,
+ ident,
+ trait_bound,
+ modifier,
+ predicate_pos,
+ bound_pos,
+ }),
+ GenericBound::Outlives(_) => None,
+ })
+ .filter(|bound| !bound.trait_bound.span.from_expansion()),
+ )
+ })
+ .flatten()
+}
+
+/// Searches the supertraits of the trait referred to by `trait_bound` recursively, returning the
+/// path taken to find a `Sized` bound if one is found
+fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> Option> {
+ fn search(cx: &LateContext<'_>, path: &mut Vec) -> bool {
+ let trait_def_id = *path.last().unwrap();
+
+ if Some(trait_def_id) == cx.tcx.lang_items().sized_trait() {
+ return true;
+ }
+
+ for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates {
+ if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && trait_predicate.polarity == PredicatePolarity::Positive
+ && !path.contains(&trait_predicate.def_id())
+ {
+ path.push(trait_predicate.def_id());
+ if search(cx, path) {
+ return true;
+ }
+ path.pop();
+ }
+ }
+
+ false
+ }
+
+ let mut path = vec![trait_bound.trait_ref.trait_def_id()?];
+ search(cx, &mut path).then_some(path)
+}
+
+impl LateLintPass<'_> for NeedlessMaybeSized {
+ fn check_generics(&mut self, cx: &LateContext<'_>, generics: &Generics<'_>) {
+ let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else {
+ return;
+ };
+
+ let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics)
+ .filter(|bound| {
+ bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait)
+ && bound.modifier == TraitBoundModifier::Maybe
+ })
+ .map(|bound| (bound.param, bound))
+ .collect();
+
+ for bound in type_param_bounds(generics) {
+ if bound.modifier == TraitBoundModifier::None
+ && let Some(sized_bound) = maybe_sized_params.get(&bound.param)
+ && let Some(path) = path_to_sized_bound(cx, bound.trait_bound)
+ {
+ span_lint_and_then(
+ cx,
+ NEEDLESS_MAYBE_SIZED,
+ sized_bound.trait_bound.span,
+ "`?Sized` bound is ignored because of a `Sized` requirement",
+ |diag| {
+ let ty_param = sized_bound.ident;
+ diag.span_note(
+ bound.trait_bound.span,
+ format!("`{ty_param}` cannot be unsized because of the bound"),
+ );
+
+ for &[current_id, next_id] in path.array_windows() {
+ let current = cx.tcx.item_name(current_id);
+ let next = cx.tcx.item_name(next_id);
+ diag.note(format!("...because `{current}` has the bound `{next}`"));
+ }
+
+ diag.span_suggestion_verbose(
+ generics.span_for_bound_removal(sized_bound.predicate_pos, sized_bound.bound_pos),
+ "change the bounds that require `Sized`, or remove the `?Sized` bound",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+
+ return;
+ }
+ }
+ }
+}
diff --git a/tests/ui-toml/type_repetition_in_bounds/main.rs b/tests/ui-toml/type_repetition_in_bounds/main.rs
index 2454c10382df..7f93d2071c9d 100644
--- a/tests/ui-toml/type_repetition_in_bounds/main.rs
+++ b/tests/ui-toml/type_repetition_in_bounds/main.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::needless_maybe_sized)]
#![warn(clippy::type_repetition_in_bounds)]
fn f()
diff --git a/tests/ui-toml/type_repetition_in_bounds/main.stderr b/tests/ui-toml/type_repetition_in_bounds/main.stderr
index 6005f76b94be..c5102c39d1cf 100644
--- a/tests/ui-toml/type_repetition_in_bounds/main.stderr
+++ b/tests/ui-toml/type_repetition_in_bounds/main.stderr
@@ -1,5 +1,5 @@
error: this type has already been used as a bound predicate
- --> tests/ui-toml/type_repetition_in_bounds/main.rs:13:5
+ --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5
|
LL | T: Unpin + PartialEq,
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs
index 3303eb145678..4a81a191e726 100644
--- a/tests/ui/auxiliary/proc_macros.rs
+++ b/tests/ui/auxiliary/proc_macros.rs
@@ -57,7 +57,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro
const ESCAPE_CHAR: char = '$';
/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their
-/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`.
+/// span set to that of the first token. Tokens may be escaped with either `$ident` or `$(tokens)`.
#[proc_macro]
pub fn with_span(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
@@ -71,7 +71,7 @@ pub fn with_span(input: TokenStream) -> TokenStream {
}
/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be
-/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`.
+/// from an external macro. Tokens may be escaped with either `$ident` or `$(tokens)`.
#[proc_macro]
pub fn external(input: TokenStream) -> TokenStream {
let mut res = TokenStream::new();
@@ -83,7 +83,7 @@ pub fn external(input: TokenStream) -> TokenStream {
}
/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped
-/// either by `#ident` or `#(tokens)`.
+/// either by `$ident` or `$(tokens)`.
fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> {
while let Some(tt) = input.next() {
match tt {
diff --git a/tests/ui/needless_maybe_sized.fixed b/tests/ui/needless_maybe_sized.fixed
new file mode 100644
index 000000000000..4d24a7cee619
--- /dev/null
+++ b/tests/ui/needless_maybe_sized.fixed
@@ -0,0 +1,116 @@
+//@aux-build:proc_macros.rs
+
+#![allow(unused, clippy::multiple_bound_locations)]
+#![warn(clippy::needless_maybe_sized)]
+
+extern crate proc_macros;
+use proc_macros::external;
+
+fn directly(t: &T) {}
+
+trait A: Sized {}
+trait B: A {}
+
+fn depth_1(t: &T) {}
+fn depth_2(t: &T) {}
+
+// We only need to show one
+fn multiple_paths(t: &T) {}
+
+fn in_where(t: &T)
+where
+ T: Sized,
+{
+}
+
+fn mixed_1(t: &T)
+{
+}
+
+fn mixed_2(t: &T)
+where
+ T: Sized,
+{
+}
+
+fn mixed_3(t: &T)
+where
+ T: Sized,
+{
+}
+
+struct Struct(T);
+
+impl Struct {
+ fn method(&self) {}
+}
+
+enum Enum {
+ Variant(&'static T),
+}
+
+union Union<'a, T: Sized> {
+ a: &'a T,
+}
+
+trait Trait {
+ fn trait_method() {}
+
+ type GAT;
+
+ type Assoc: Sized + ?Sized; // False negative
+}
+
+trait SecondInTrait: Send + Sized {}
+fn second_in_trait() {}
+
+fn impl_trait(_: &(impl Sized)) {}
+
+trait GenericTrait: Sized {}
+fn in_generic_trait, U>() {}
+
+mod larger_graph {
+ // C1 C2 Sized
+ // \ /\ /
+ // B1 B2
+ // \ /
+ // A1
+
+ trait C1 {}
+ trait C2 {}
+ trait B1: C1 + C2 {}
+ trait B2: C2 + Sized {}
+ trait A1: B1 + B2 {}
+
+ fn larger_graph() {}
+}
+
+// Should not lint
+
+fn sized() {}
+fn maybe_sized() {}
+
+struct SeparateBounds(T);
+impl SeparateBounds {}
+
+trait P {}
+trait Q: P {}
+
+fn ok_depth_1() {}
+fn ok_depth_2() {}
+
+external! {
+ fn in_macro(t: &T) {}
+
+ fn with_local_clone(t: &T) {}
+}
+
+#[derive(Clone)]
+struct InDerive {
+ t: T,
+}
+
+struct Refined(T);
+impl Refined {}
+
+fn main() {}
diff --git a/tests/ui/needless_maybe_sized.rs b/tests/ui/needless_maybe_sized.rs
new file mode 100644
index 000000000000..ef66f9a4f2ae
--- /dev/null
+++ b/tests/ui/needless_maybe_sized.rs
@@ -0,0 +1,119 @@
+//@aux-build:proc_macros.rs
+
+#![allow(unused, clippy::multiple_bound_locations)]
+#![warn(clippy::needless_maybe_sized)]
+
+extern crate proc_macros;
+use proc_macros::external;
+
+fn directly(t: &T) {}
+
+trait A: Sized {}
+trait B: A {}
+
+fn depth_1(t: &T) {}
+fn depth_2(t: &T) {}
+
+// We only need to show one
+fn multiple_paths(t: &T) {}
+
+fn in_where(t: &T)
+where
+ T: Sized + ?Sized,
+{
+}
+
+fn mixed_1(t: &T)
+where
+ T: ?Sized,
+{
+}
+
+fn mixed_2(t: &T)
+where
+ T: Sized,
+{
+}
+
+fn mixed_3(t: &T)
+where
+ T: Sized,
+ T: ?Sized,
+{
+}
+
+struct Struct(T);
+
+impl Struct {
+ fn method(&self) {}
+}
+
+enum Enum {
+ Variant(&'static T),
+}
+
+union Union<'a, T: Sized + ?Sized> {
+ a: &'a T,
+}
+
+trait Trait {
+ fn trait_method() {}
+
+ type GAT;
+
+ type Assoc: Sized + ?Sized; // False negative
+}
+
+trait SecondInTrait: Send + Sized {}
+fn second_in_trait() {}
+
+fn impl_trait(_: &(impl Sized + ?Sized)) {}
+
+trait GenericTrait: Sized {}
+fn in_generic_trait + ?Sized, U>() {}
+
+mod larger_graph {
+ // C1 C2 Sized
+ // \ /\ /
+ // B1 B2
+ // \ /
+ // A1
+
+ trait C1 {}
+ trait C2 {}
+ trait B1: C1 + C2 {}
+ trait B2: C2 + Sized {}
+ trait A1: B1 + B2 {}
+
+ fn larger_graph() {}
+}
+
+// Should not lint
+
+fn sized() {}
+fn maybe_sized() {}
+
+struct SeparateBounds(T);
+impl SeparateBounds {}
+
+trait P {}
+trait Q: P {}
+
+fn ok_depth_1() {}
+fn ok_depth_2() {}
+
+external! {
+ fn in_macro(t: &T) {}
+
+ fn with_local_clone(t: &T) {}
+}
+
+#[derive(Clone)]
+struct InDerive {
+ t: T,
+}
+
+struct Refined(T);
+impl Refined {}
+
+fn main() {}
diff --git a/tests/ui/needless_maybe_sized.stderr b/tests/ui/needless_maybe_sized.stderr
new file mode 100644
index 000000000000..3b1d2b49b062
--- /dev/null
+++ b/tests/ui/needless_maybe_sized.stderr
@@ -0,0 +1,353 @@
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:9:24
+ |
+LL | fn directly(t: &T) {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:9:16
+ |
+LL | fn directly(t: &T) {}
+ | ^^^^^
+ = note: `-D clippy::needless-maybe-sized` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::needless_maybe_sized)]`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn directly(t: &T) {}
+LL + fn directly(t: &T) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:14:19
+ |
+LL | fn depth_1(t: &T) {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:14:15
+ |
+LL | fn depth_1(t: &T) {}
+ | ^
+ = note: ...because `A` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn depth_1(t: &T) {}
+LL + fn depth_1(t: &T) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:15:19
+ |
+LL | fn depth_2(t: &T) {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:15:15
+ |
+LL | fn depth_2(t: &T) {}
+ | ^
+ = note: ...because `B` has the bound `A`
+ = note: ...because `A` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn depth_2(t: &T) {}
+LL + fn depth_2(t: &T) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:18:30
+ |
+LL | fn multiple_paths(t: &T) {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:18:22
+ |
+LL | fn multiple_paths(t: &T) {}
+ | ^
+ = note: ...because `A` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn multiple_paths(t: &T) {}
+LL + fn multiple_paths(t: &T) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:22:16
+ |
+LL | T: Sized + ?Sized,
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:22:8
+ |
+LL | T: Sized + ?Sized,
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - T: Sized + ?Sized,
+LL + T: Sized,
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:28:8
+ |
+LL | T: ?Sized,
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:26:15
+ |
+LL | fn mixed_1(t: &T)
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - where
+LL - T: ?Sized,
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:32:15
+ |
+LL | fn mixed_2(t: &T)
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:34:8
+ |
+LL | T: Sized,
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn mixed_2(t: &T)
+LL + fn mixed_2(t: &T)
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:41:8
+ |
+LL | T: ?Sized,
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:40:8
+ |
+LL | T: Sized,
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - T: Sized,
+LL - T: ?Sized,
+LL + T: Sized,
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:45:26
+ |
+LL | struct Struct(T);
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:45:18
+ |
+LL | struct Struct(T);
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - struct Struct(T);
+LL + struct Struct(T);
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:47:17
+ |
+LL | impl Struct {
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:47:9
+ |
+LL | impl Struct {
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - impl Struct {
+LL + impl Struct {
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:48:26
+ |
+LL | fn method(&self) {}
+ | ^^^^^^
+ |
+note: `U` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:48:18
+ |
+LL | fn method(&self) {}
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn method(&self) {}
+LL + fn method(&self) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:51:22
+ |
+LL | enum Enum {
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:51:14
+ |
+LL | enum Enum {
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - enum Enum {
+LL + enum Enum {
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:55:28
+ |
+LL | union Union<'a, T: Sized + ?Sized> {
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:55:20
+ |
+LL | union Union<'a, T: Sized + ?Sized> {
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - union Union<'a, T: Sized + ?Sized> {
+LL + union Union<'a, T: Sized> {
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:59:24
+ |
+LL | trait Trait {
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:59:16
+ |
+LL | trait Trait {
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - trait Trait {
+LL + trait Trait {
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:60:32
+ |
+LL | fn trait_method() {}
+ | ^^^^^^
+ |
+note: `U` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:60:24
+ |
+LL | fn trait_method() {}
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn trait_method() {}
+LL + fn trait_method() {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:62:25
+ |
+LL | type GAT;
+ | ^^^^^^
+ |
+note: `U` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:62:17
+ |
+LL | type GAT;
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - type GAT;
+LL + type GAT;
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:68:23
+ |
+LL | fn second_in_trait() {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:68:32
+ |
+LL | fn second_in_trait() {}
+ | ^^^^^^^^^^^^^
+ = note: ...because `SecondInTrait` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn second_in_trait() {}
+LL + fn second_in_trait() {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:70:33
+ |
+LL | fn impl_trait(_: &(impl Sized + ?Sized)) {}
+ | ^^^^^^
+ |
+note: `impl Sized + ?Sized` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:70:25
+ |
+LL | fn impl_trait(_: &(impl Sized + ?Sized)) {}
+ | ^^^^^
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn impl_trait(_: &(impl Sized + ?Sized)) {}
+LL + fn impl_trait(_: &(impl Sized)) {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:73:42
+ |
+LL | fn in_generic_trait + ?Sized, U>() {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:73:24
+ |
+LL | fn in_generic_trait + ?Sized, U>() {}
+ | ^^^^^^^^^^^^^^^
+ = note: ...because `GenericTrait` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn in_generic_trait + ?Sized, U>() {}
+LL + fn in_generic_trait, U>() {}
+ |
+
+error: `?Sized` bound is ignored because of a `Sized` requirement
+ --> tests/ui/needless_maybe_sized.rs:88:29
+ |
+LL | fn larger_graph() {}
+ | ^^^^^^
+ |
+note: `T` cannot be unsized because of the bound
+ --> tests/ui/needless_maybe_sized.rs:88:24
+ |
+LL | fn larger_graph() {}
+ | ^^
+ = note: ...because `A1` has the bound `B2`
+ = note: ...because `B2` has the bound `Sized`
+help: change the bounds that require `Sized`, or remove the `?Sized` bound
+ |
+LL - fn larger_graph() {}
+LL + fn larger_graph() {}
+ |
+
+error: aborting due to 20 previous errors
+
diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs
index 0039c805b7df..d325887bfba3 100644
--- a/tests/ui/type_repetition_in_bounds.rs
+++ b/tests/ui/type_repetition_in_bounds.rs
@@ -1,5 +1,9 @@
#![deny(clippy::type_repetition_in_bounds)]
-#![allow(clippy::extra_unused_type_parameters, clippy::multiple_bound_locations)]
+#![allow(
+ clippy::extra_unused_type_parameters,
+ clippy::multiple_bound_locations,
+ clippy::needless_maybe_sized
+)]
use serde::Deserialize;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr
index e9c6b41aaa8e..77944c950457 100644
--- a/tests/ui/type_repetition_in_bounds.stderr
+++ b/tests/ui/type_repetition_in_bounds.stderr
@@ -1,5 +1,5 @@
error: this type has already been used as a bound predicate
- --> tests/ui/type_repetition_in_bounds.rs:10:5
+ --> tests/ui/type_repetition_in_bounds.rs:14:5
|
LL | T: Clone,
| ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this type has already been used as a bound predicate
- --> tests/ui/type_repetition_in_bounds.rs:28:5
+ --> tests/ui/type_repetition_in_bounds.rs:32:5
|
LL | Self: Copy + Default + Ord,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord,
= help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
error: this type has already been used as a bound predicate
- --> tests/ui/type_repetition_in_bounds.rs:103:5
+ --> tests/ui/type_repetition_in_bounds.rs:107:5
|
LL | T: Clone,
| ^^^^^^^^
@@ -28,7 +28,7 @@ LL | T: Clone,
= help: consider combining the bounds: `T: ?Sized + Clone`
error: this type has already been used as a bound predicate
- --> tests/ui/type_repetition_in_bounds.rs:109:5
+ --> tests/ui/type_repetition_in_bounds.rs:113:5
|
LL | T: ?Sized,
| ^^^^^^^^^
@@ -36,7 +36,7 @@ LL | T: ?Sized,
= help: consider combining the bounds: `T: Clone + ?Sized`
error: this type has already been used as a bound predicate
- --> tests/ui/type_repetition_in_bounds.rs:135:9
+ --> tests/ui/type_repetition_in_bounds.rs:139:9
|
LL | T: Trait