From 2326f42ce2529330ffbd1b865b90338bd4bf17fd Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Tue, 25 Oct 2022 18:07:21 +0530 Subject: [PATCH 001/251] stabilise array methods --- library/alloc/src/lib.rs | 1 - library/core/src/array/mod.rs | 9 ++------- library/core/tests/lib.rs | 1 - src/librustdoc/lib.rs | 1 - 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ce36b116f139..a222871a8465 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,7 +92,6 @@ #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_into_iter_constructors)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(assert_matches)] #![feature(async_iterator)] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index eae0e1c76186..5fbf15f1a28b 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -592,8 +592,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] - /// /// let floats = [3.1, 2.7, -1.0]; /// let float_refs: [&f64; 3] = floats.each_ref(); /// assert_eq!(float_refs, [&3.1, &2.7, &-1.0]); @@ -604,8 +602,6 @@ impl [T; N] { /// array if its elements are not [`Copy`]. /// /// ``` - /// #![feature(array_methods)] - /// /// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()]; /// let is_ascii = strings.each_ref().map(|s| s.is_ascii()); /// assert_eq!(is_ascii, [true, false, true]); @@ -613,7 +609,7 @@ impl [T; N] { /// // We can still access the original array: it has not been moved. /// assert_eq!(strings.len(), 3); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_ref(&self) -> [&T; N] { // SAFETY: we know for certain that this iterator will yield exactly `N` // items. @@ -627,7 +623,6 @@ impl [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] /// /// let mut floats = [3.1, 2.7, -1.0]; /// let float_refs: [&mut f64; 3] = floats.each_mut(); @@ -635,7 +630,7 @@ impl [T; N] { /// assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]); /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_mut(&mut self) -> [&mut T; N] { // SAFETY: we know for certain that this iterator will yield exactly `N` // items. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3012a78b9c98..dda8d27605b7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(bigint_helper_methods)] #![feature(cell_update)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 793061a9f7a0..f6b065505530 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,7 +3,6 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] -#![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] From cce93f0a04ebaa4a1807f2e7f43d47839926ba94 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 10:35:08 +0000 Subject: [PATCH 002/251] Add `str::Lines::remainder` --- library/core/src/str/iter.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index d969475aa484..fffa421a6462 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1137,6 +1137,31 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Lines<'_> {} +impl<'a> Lines<'a> { + /// Returns the remaining lines of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_lines_remainder)] + /// + /// let mut lines = "a\nb\nc\nd".lines(); + /// assert_eq!(lines.remainder(), Some("a\nb\nc\nd")); + /// + /// lines.next(); + /// assert_eq!(lines.remainder(), Some("b\nc\nd")); + /// + /// lines.by_ref().for_each(drop); + /// assert_eq!(lines.remainder(), None); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "str_lines_remainder", issue = "77998")] + pub fn remainder(&self) -> Option<&'a str> { + self.0.iter.remainder() + } +} + /// Created with the method [`lines_any`]. /// /// [`lines_any`]: str::lines_any From bab8d29887a0d801fe72f922dafe75a635bc9198 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Sat, 8 Jul 2023 19:55:33 +0200 Subject: [PATCH 003/251] impl `From<&[T; N]>` for `Cow<[T]>` --- library/alloc/src/vec/cow.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 2c799605b7b6..7d2462ee32e0 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,6 +15,19 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } +#[unstable(feature = "cow_from_array_ref", issue = "none")] +impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a reference to an array. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed + fn from(s: &'a [T; N]) -> Cow<'a, [T]> { + Cow::Borrowed(s as &[_]) + } +} + #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From> for Cow<'a, [T]> { /// Creates an [`Owned`] variant of [`Cow`] From 6bfad315265cc36d461dedf19f64e445c872da0c Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Sat, 8 Jul 2023 20:11:47 +0200 Subject: [PATCH 004/251] mark as stable --- library/alloc/src/vec/cow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 7d2462ee32e0..b12910f3690b 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,7 +15,7 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } -#[unstable(feature = "cow_from_array_ref", issue = "none")] +#[stable(feature = "cow_from_array_ref", since = "CURRENT_RUSTC_VERSION")] impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { /// Creates a [`Borrowed`] variant of [`Cow`] /// from a reference to an array. From a20866254c6864e49814d6abd47a37fd01bcff0a Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 15:35:03 -0700 Subject: [PATCH 005/251] References refer to allocated objects --- library/core/src/primitive_docs.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 380a21b376bd..e73d5f990cba 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1389,6 +1389,18 @@ mod prim_usize {} /// work on references as well as they do on owned values! The implementations described here are /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not /// locally known. +/// +/// # Safety +/// +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that +/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` +/// which violates any of these properties. +/// +/// * `t` is aligned to `align_of_val(t)` +/// * `t` refers to a valid instance of `T` +/// * `t` refers to a single [allocated object] +/// +/// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} From 4f0192a756f756db6bd1c25a8dbe6e89f0086661 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 12 Oct 2023 18:55:45 -0700 Subject: [PATCH 006/251] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index e73d5f990cba..04ae8c223f2c 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,6 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a valid instance of `T` /// * `t` refers to a single [allocated object] /// /// [allocated object]: ptr#allocated-object From 39660c4a77d3dda7f5d57a8d91faa946fff5192b Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:47:39 -0700 Subject: [PATCH 007/251] Update library/core/src/primitive_docs.rs Co-authored-by: Ralf Jung --- library/core/src/primitive_docs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 04ae8c223f2c..cde49aeb687f 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1397,7 +1397,11 @@ mod prim_usize {} /// which violates any of these properties. /// /// * `t` is aligned to `align_of_val(t)` -/// * `t` refers to a single [allocated object] +/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// +/// Being "dereferenceable" for N bytes means that the memory range beginning +/// at the address `t` points to and ending N bytes later is all contained within a +/// single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 55487e235b106088ced4e5b4710fa8f9674baaf9 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 13 Oct 2023 09:49:23 -0700 Subject: [PATCH 008/251] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index cde49aeb687f..19ff41697d9f 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1399,9 +1399,8 @@ mod prim_usize {} /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes /// -/// Being "dereferenceable" for N bytes means that the memory range beginning -/// at the address `t` points to and ending N bytes later is all contained within a -/// single [allocated object]. +/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range +/// `[a, a + N)` is all contained within a single [allocated object]. /// /// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] From 42b1406d9e0be812b1faeefcdd7c61fd788e1043 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 30 Oct 2023 21:16:23 -0400 Subject: [PATCH 009/251] Make `allow_internal_unstable` work with `stmt_expr_attributes` --- compiler/rustc_expand/src/config.rs | 4 +++- tests/ui/internal/internal-unstable.rs | 10 ++++++++++ tests/ui/internal/internal-unstable.stderr | 8 ++++---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index bef48765937f..438796218d44 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -449,7 +449,9 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) { + if self.features.is_some_and(|features| !features.stmt_expr_attributes) + && !attr.span.allows_unstable(sym::stmt_expr_attributes) + { let mut err = feature_err( &self.sess.parse_sess, sym::stmt_expr_attributes, diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index 1eb27fbdc3a6..a4445fefef57 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -28,6 +28,14 @@ macro_rules! bar { }} } +#[allow_internal_unstable(stmt_expr_attributes)] +macro_rules! internal_attr { + ($e: expr) => { + #[allow(overflowing_literals)] + $e + } +} + fn main() { // ok, the instability is contained. call_unstable_allow!(); @@ -51,4 +59,6 @@ fn main() { #[allow_internal_unstable] _ => {} } + + assert_eq!(internal_attr!(1e100_f32), f32::INFINITY); } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index b7c47365c2d2..cf741505fa42 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:40:25 + --> $DIR/internal-unstable.rs:48:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:42:27 + --> $DIR/internal-unstable.rs:50:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:46:22 + --> $DIR/internal-unstable.rs:54:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:48:10 + --> $DIR/internal-unstable.rs:56:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 1a0309afb62b01002c1ac2466a6af0dc69594596 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 3 Nov 2023 06:41:23 -0700 Subject: [PATCH 010/251] Update primitive_docs.rs --- library/core/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 19ff41697d9f..939342c4d976 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1393,8 +1393,9 @@ mod prim_usize {} /// # Safety /// /// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, unsafe code may assume that -/// the following properties hold. It is undefined behavior to produce a `t: &T` or `t: &mut T` -/// which violates any of these properties. +/// the following properties hold. Rust programmers must assume that, unless explicitly stated +/// otherwise, any Rust code they did not author themselves may rely on these properties, and that +/// violating them may cause that code to exhibit undefined behavior. /// /// * `t` is aligned to `align_of_val(t)` /// * `t` is dereferenceable for `size_of_val(t)` many bytes From 8c79f7840d399e3de52c63b1951a46adf6dda515 Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 7 Nov 2023 17:57:31 +0800 Subject: [PATCH 011/251] `read_zero_byte_vec` refactor for better heuristics --- clippy_lints/src/read_zero_byte_vec.rs | 118 +++++++++++++++---------- tests/ui/read_zero_byte_vec.rs | 29 ++++-- tests/ui/read_zero_byte_vec.stderr | 34 ++++--- 3 files changed, 112 insertions(+), 69 deletions(-) diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index b27d4cc6e4f8..f5a8287d2e09 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; -use core::ops::ControlFlow; -use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; + +use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -49,57 +51,40 @@ declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { - for (idx, stmt) in block.stmts.iter().enumerate() { - if !stmt.span.from_expansion() - // matches `let v = Vec::new();` - && let StmtKind::Local(local) = stmt.kind - && let Local { pat, init: Some(init), .. } = local - && let PatKind::Binding(_, _, ident, _) = pat.kind + for stmt in block.stmts { + if stmt.span.from_expansion() { + return; + } + + if let StmtKind::Local(local) = stmt.kind + && let Local { + pat, init: Some(init), .. + } = local + && let PatKind::Binding(_, id, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - let visitor = |expr: &Expr<'_>| { - if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { - ident: read_or_read_exact, - .. - } = *path - && matches!(read_or_read_exact.as_str(), "read" | "read_exact") - && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind - && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind - && let [inner_seg] = inner_path.segments - && ident.name == inner_seg.ident.name - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + let mut visitor = ReadVecVisitor { + local_id: id, + read_zero_expr: None, + has_resize: false, }; - let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { - // case { .. stmt; stmt; .. } - (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) - } else if let Some(e) = block.expr { - // case { .. stmt; expr } - (for_each_expr(e, visitor).is_some(), e.span) - } else { + let Some(enclosing_block) = get_enclosing_block(cx, id) else { return; }; + visitor.visit_block(enclosing_block); - if read_found && !next_stmt_span.from_expansion() { + if let Some(expr) = visitor.read_zero_expr { let applicability = Applicability::MaybeIncorrect; match vec_init_kind { VecInitKind::WithConstCapacity(len) => { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", - format!( - "{}.resize({len}, 0); {}", - ident.as_str(), - snippet(cx, next_stmt_span, "..") - ), + format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), applicability, ); }, @@ -108,25 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", format!( "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), - snippet(cx, next_stmt_span, "..") + snippet(cx, expr.span, "..") ), applicability, ); }, _ => { - span_lint( - cx, - READ_ZERO_BYTE_VEC, - next_stmt_span, - "reading zero byte data to `Vec`", - ); + span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`"); }, } } @@ -134,3 +114,47 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } } } + +struct ReadVecVisitor<'tcx> { + local_id: HirId, + read_zero_expr: Option<&'tcx Expr<'tcx>>, + has_resize: bool, +} + +impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { + let PathSegment { ident, .. } = *path; + + match ident.as_str() { + "read" | "read_exact" => { + let [arg] = args else { return }; + if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind + && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind + && let [inner_seg] = inner_path.segments + && let Res::Local(res_id) = inner_seg.res + && self.local_id == res_id + { + self.read_zero_expr = Some(e); + return; + } + }, + "resize" => { + // If the Vec is resized, then it's a valid read + if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind + && let Res::Local(res_id) = inner_path.res + && self.local_id == res_id + { + self.has_resize = true; + return; + } + }, + _ => {}, + } + } + + if !self.has_resize && self.read_zero_expr.is_none() { + walk_expr(self, e); + } + } +} diff --git a/tests/ui/read_zero_byte_vec.rs b/tests/ui/read_zero_byte_vec.rs index 76b9b9818511..fd5a88a37a66 100644 --- a/tests/ui/read_zero_byte_vec.rs +++ b/tests/ui/read_zero_byte_vec.rs @@ -55,14 +55,6 @@ fn test() -> io::Result<()> { let mut buf = [0u8; 100]; f.read(&mut buf)?; - // should not lint - let mut empty = vec![]; - let mut data7 = vec![]; - f.read(&mut empty); - - // should not lint - f.read(&mut data7); - // should not lint let mut data8 = Vec::new(); data8.resize(100, 0); @@ -75,6 +67,27 @@ fn test() -> io::Result<()> { Ok(()) } +fn test_nested() -> io::Result<()> { + let cap = 1000; + let mut f = File::open("foo.txt").unwrap(); + + // Issue #9274 + // Should not lint + let mut v = Vec::new(); + { + v.resize(10, 0); + f.read(&mut v)?; + } + + let mut v = Vec::new(); + { + f.read(&mut v)?; + //~^ ERROR: reading zero byte data to `Vec` + } + + Ok(()) +} + async fn test_futures(r: &mut R) { // should lint let mut data = Vec::new(); diff --git a/tests/ui/read_zero_byte_vec.stderr b/tests/ui/read_zero_byte_vec.stderr index 523ecb2948df..e85aa051c34b 100644 --- a/tests/ui/read_zero_byte_vec.stderr +++ b/tests/ui/read_zero_byte_vec.stderr @@ -2,7 +2,7 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:21:5 | LL | f.read_exact(&mut data).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)` | = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` @@ -11,19 +11,19 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:27:5 | LL | f.read_exact(&mut data2)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)` error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:32:5 | LL | f.read_exact(&mut data3)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:37:5 + --> $DIR/read_zero_byte_vec.rs:37:13 | LL | let _ = f.read(&mut data4)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:43:9 @@ -38,28 +38,34 @@ LL | f.read(&mut data6) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:81:5 + --> $DIR/read_zero_byte_vec.rs:84:9 + | +LL | f.read(&mut v)?; + | ^^^^^^^^^^^^^^ + +error: reading zero byte data to `Vec` + --> $DIR/read_zero_byte_vec.rs:94:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:86:5 + --> $DIR/read_zero_byte_vec.rs:99:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:93:5 + --> $DIR/read_zero_byte_vec.rs:106:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:98:5 + --> $DIR/read_zero_byte_vec.rs:111:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From 0bccdb34a20643ae1bd07ee6f3f0156640a12120 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 7 Nov 2023 17:46:00 +0100 Subject: [PATCH 012/251] Stabilize `slice_group_by` Renamed "group by" to "chunk by" a per #80552. Newly stable items: * `core::slice::ChunkBy` * `core::slice::ChunkByMut` * `[T]::chunk` * `[T]::chunk_by` Closes #80552. --- library/alloc/src/lib.rs | 1 - library/alloc/src/slice.rs | 4 +-- library/alloc/tests/lib.rs | 1 - library/alloc/tests/slice.rs | 16 ++++----- library/core/src/slice/iter.rs | 64 +++++++++++++++++----------------- library/core/src/slice/mod.rs | 32 +++++++---------- library/core/tests/lib.rs | 1 - 7 files changed, 54 insertions(+), 65 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 02ecbe22b3e1..7d04a2964037 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -149,7 +149,6 @@ #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] -#![feature(slice_group_by)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index aa3b7b7e1914..4033f4eb068c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -51,14 +51,14 @@ pub use core::slice::{from_mut, from_ref}; pub use core::slice::{from_mut_ptr_range, from_ptr_range}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Chunks, Windows}; #[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{ChunksMut, Split, SplitMut}; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use core::slice::{GroupBy, GroupByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Iter, IterMut}; #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 2dcfc6b4abfe..ca17dab55b02 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -29,7 +29,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(round_char_boundary)] -#![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(string_remove_matches)] #![feature(const_btree_len)] diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 784839a3ffa4..c0f7a11a93e1 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1614,10 +1614,10 @@ fn subslice_patterns() { } #[test] -fn test_group_by() { +fn test_chunk_by() { let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); @@ -1625,7 +1625,7 @@ fn test_group_by() { assert_eq!(iter.next(), Some(&[0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); @@ -1633,7 +1633,7 @@ fn test_group_by() { assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1643,10 +1643,10 @@ fn test_group_by() { } #[test] -fn test_group_by_mut() { +fn test_chunk_by_mut() { let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); @@ -1654,7 +1654,7 @@ fn test_group_by_mut() { assert_eq!(iter.next(), Some(&mut [0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next_back(), Some(&mut [1][..])); assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); @@ -1662,7 +1662,7 @@ fn test_group_by_mut() { assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1c65475b81d7..2d4c7e78aea1 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3248,26 +3248,26 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// -/// This struct is created by the [`group_by`] method on [slices]. +/// This struct is created by the [`chunk_by`] method on [slices]. /// -/// [`group_by`]: slice::group_by +/// [`chunk_by`]: slice::chunk_by /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupBy<'a, T: 'a, P> { +pub struct ChunkBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkBy<'a, T, P> { pub(super) fn new(slice: &'a [T], predicate: P) -> Self { - GroupBy { slice, predicate } + ChunkBy { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3300,8 +3300,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3322,39 +3322,39 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupBy").field("slice", &self.slice).finish() + f.debug_struct("ChunkBy").field("slice", &self.slice).finish() } } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. /// -/// This struct is created by the [`group_by_mut`] method on [slices]. +/// This struct is created by the [`chunk_by_mut`] method on [slices]. /// -/// [`group_by_mut`]: slice::group_by_mut +/// [`chunk_by_mut`]: slice::chunk_by_mut /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupByMut<'a, T: 'a, P> { +pub struct ChunkByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkByMut<'a, T, P> { pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { - GroupByMut { slice, predicate } + ChunkByMut { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3388,8 +3388,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3411,12 +3411,12 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkByMut<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupByMut").field("slice", &self.slice).finish() + f.debug_struct("ChunkByMut").field("slice", &self.slice).finish() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 27dda478848c..fe18c31df1a8 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -68,8 +68,8 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use iter::{GroupBy, GroupByMut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use iter::{ChunkBy, ChunkByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; @@ -1755,11 +1755,9 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by(|a, b| a == b); + /// let mut iter = slice.chunk_by(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1770,24 +1768,22 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by(|a, b| a <= b); + /// let mut iter = slice.chunk_by(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> + pub fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupBy::new(self, pred) + ChunkBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable @@ -1800,11 +1796,9 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by_mut(|a, b| a == b); + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); @@ -1815,24 +1809,22 @@ impl [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by_mut(|a, b| a <= b); + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> + pub fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupByMut::new(self, pred) + ChunkByMut::new(self, pred) } /// Divides one slice into two at an index. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 89d2b5ef0938..57ad2ad1af9a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -101,7 +101,6 @@ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] -#![feature(slice_group_by)] #![feature(split_array)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] From c5c2fb1761e0962c66793f6753cbe8f0cc2d4c26 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 17 Nov 2023 12:35:46 +0100 Subject: [PATCH 013/251] Improve slice_group_by doc wording --- library/core/src/slice/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index fe18c31df1a8..2d93ef6fbeb3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1748,9 +1748,9 @@ impl [T] { /// Returns an iterator over the slice producing non-overlapping runs /// of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// @@ -1789,9 +1789,9 @@ impl [T] { /// Returns an iterator over the slice producing non-overlapping mutable /// runs of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// From 4369a787300c22110ae5ea8d520870fd8bc975a0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:16:02 +0100 Subject: [PATCH 014/251] Add triagebot mentions entry for simd intrinsics --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index e4b104cdb867..8dcfb38e097b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -492,6 +492,13 @@ cc = ["@Nadrieril"] message = "Some changes might have occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."library/core/src/intrinsics/simd.rs"] +message = """ +Some changes occurred to the platform-builtins intrinsics. Make sure all +codegen backends as well as portable-simd get adapted for the changes. +""" +cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] + [mentions."library/portable-simd"] message = """ Portable SIMD is developed in its own repository. If possible, consider \ From adb6e1b69bfba1e57ba5606797848199733e0f96 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 26 Dec 2023 12:42:40 +0100 Subject: [PATCH 015/251] Update triagebot.toml --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 8dcfb38e097b..6acc698ec1b1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -494,8 +494,8 @@ cc = ["@Nadrieril"] [mentions."library/core/src/intrinsics/simd.rs"] message = """ -Some changes occurred to the platform-builtins intrinsics. Make sure all -codegen backends as well as portable-simd get adapted for the changes. +Some changes occurred to the platform-builtins intrinsics. Make sure the +LLVM backend as well as portable-simd gets adapted for the changes. """ cc = ["@antoyo", "@GuillaumeGomez", "@bjorn3", "@calebzulawski", "@programmerjake"] From 42afefa09b30bff7699275ee5ccb33b79c54d90c Mon Sep 17 00:00:00 2001 From: Sky Date: Sun, 31 Dec 2023 00:02:08 -0500 Subject: [PATCH 016/251] Initial implementation of `str::from_raw_parts[_mut]` --- library/core/src/str/converts.rs | 40 +++++++++++++++++++++++++++++++- library/core/src/str/mod.rs | 3 +++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 0f23cf7ae239..ba282f09d206 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,6 +1,6 @@ //! Ways to create a `str` from bytes slice. -use crate::mem; +use crate::{mem, ptr}; use super::validations::run_utf8_validation; use super::Utf8Error; @@ -205,3 +205,41 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // comes from a reference which is guaranteed to be valid for writes. unsafe { &mut *(v as *mut [u8] as *mut str) } } + +/// Creates an `&str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts`](crate::slice::from_raw_parts). +/// See that function's documentation for safety concerns and examples. +/// +/// The mutable version of this function is [`from_raw_parts_mut`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] +pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::from_raw_parts(ptr.cast(), len) } +} + +/// Creates an `&mut str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts_mut`](crate::slice::from_raw_parts_mut). +/// See that function's documentation for safety concerns and examples. +/// +/// The immutable version of this function is [`from_raw_parts`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] +pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::from_raw_parts_mut(ptr.cast(), len) } +} diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index a22c46edce25..2981d1206dd5 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -33,6 +33,9 @@ pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use converts::{from_raw_parts, from_raw_parts_mut}; + #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; From 0cfbc47b9a32735659f8347872c571bdfeba8424 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:29:53 +0000 Subject: [PATCH 017/251] Merge commit '6d355f6844323db03bfd608899613e363e701951' into sync_cg_clif-2023-12-31 --- .github/workflows/main.yml | 16 ++++++---------- .github/workflows/rustc.yml | 5 +++++ rust-toolchain | 2 +- scripts/setup_rust_fork.sh | 15 +++++++-------- src/driver/jit.rs | 2 +- src/global_asm.rs | 2 ++ 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05dc28d07453..9bbb18fc37fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -175,14 +175,10 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Cache cargo bin dir - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Install hyperfine - run: cargo install hyperfine || true + run: | + sudo apt update + sudo apt install -y hyperfine - name: Prepare dependencies run: ./y.sh prepare @@ -257,14 +253,14 @@ jobs: - name: Upload prebuilt cg_clif if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - name: Upload prebuilt cg_clif (cross compile) if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ runner.os }}-cross-x86_64-mingw path: cg_clif.tar.xz @@ -283,7 +279,7 @@ jobs: - uses: actions/checkout@v3 - name: Download all built artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts/ diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index cb5dd51fee31..8085dc58263c 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -43,6 +43,11 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + - name: Install ripgrep + run: | + sudo apt update + sudo apt install -y ripgrep + - name: Prepare dependencies run: ./y.sh prepare diff --git a/rust-toolchain b/rust-toolchain index e1e1760c5977..a086c0293601 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-24" +channel = "nightly-2023-12-31" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 731828caae2c..684a5d072935 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we +# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as # the LLVM backend isn't compiled in here. export CG_CLIF_FORCE_GNU_AS=1 @@ -11,20 +11,19 @@ export CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build echo "[SETUP] Rust fork" -git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true +git clone --quiet https://github.com/rust-lang/rust.git --filter=tree:0 || true pushd rust git fetch -git checkout -- . -git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" +git checkout --no-progress -- . +git checkout --no-progress "$(rustc -V | cut -d' ' -f3 | tr -d '(')" + +git submodule update --quiet --init src/tools/cargo library/backtrace library/stdarch git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ am ../patches/*-stdlib-*.patch cat > config.toml < {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.struct_err(format!("Can't load static lib {}", name)); + let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); err.emit(); } diff --git a/src/global_asm.rs b/src/global_asm.rs index af99239d8159..da07b66c762e 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -154,6 +154,8 @@ pub(crate) fn compile_global_asm( } } else { let mut child = Command::new(std::env::current_exe().unwrap()) + // Avoid a warning about the jobserver fd not being passed + .env_remove("CARGO_MAKEFLAGS") .arg("--target") .arg(&config.target) .arg("--crate-type") From 543d56938e23865eb70b49f153c71a2057668c79 Mon Sep 17 00:00:00 2001 From: Aneesh Kadiyala <143342960+ARandomDev99@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:30:20 +0530 Subject: [PATCH 018/251] Make `HirEqInterExpr::eq_block` take comments into account This commit: - now makes `HirEqInterExpr::eq_block` take comments into account. Identical code with varying comments will no longer be considered equal. - makes necessary adjustments to UI tests. --- clippy_utils/src/hir_utils.rs | 6 +- .../ui/branches_sharing_code/shared_at_top.rs | 8 +-- .../shared_at_top.stderr | 6 +- .../branches_sharing_code/valid_if_blocks.rs | 12 ++-- .../valid_if_blocks.stderr | 18 ++--- tests/ui/if_same_then_else.rs | 28 +++----- tests/ui/if_same_then_else.stderr | 69 +++++++------------ tests/ui/if_same_then_else2.rs | 18 ++--- tests/ui/if_same_then_else2.stderr | 37 ++++------ tests/ui/match_same_arms2.rs | 4 +- tests/ui/match_same_arms2.stderr | 5 +- 11 files changed, 73 insertions(+), 138 deletions(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index e610ed930505..ea8d3631b0d2 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -134,7 +134,7 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + use TokenKind::{Semi, Whitespace}; if left.stmts.len() != right.stmts.len() { return false; } @@ -177,7 +177,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) { return false; } @@ -212,7 +212,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) } diff --git a/tests/ui/branches_sharing_code/shared_at_top.rs b/tests/ui/branches_sharing_code/shared_at_top.rs index 44f8b2eabce3..9af81f6f7cdd 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/tests/ui/branches_sharing_code/shared_at_top.rs @@ -9,17 +9,16 @@ fn simple_examples() { // Simple if true { - //~^ ERROR: all if blocks contain the same code at the start println!("Hello World!"); println!("I'm branch nr: 1"); } else { println!("Hello World!"); println!("I'm branch nr: 2"); } + //~^^^^^^^ ERROR: all if blocks contain the same code at the start // Else if if x == 0 { - //~^ ERROR: all if blocks contain the same code at the start let y = 9; println!("The value y was set to: `{}`", y); let _z = y; @@ -38,6 +37,7 @@ fn simple_examples() { println!("Ha, Pascal allows you to start the array where you want") } + //~^^^^^^^^^^^^^^^^^^^ ERROR: all if blocks contain the same code at the start // Return a value let _ = if x == 7 { @@ -60,7 +60,6 @@ fn simple_but_suggestion_is_invalid() { // Can't be automatically moved because used_value_name is getting used again let used_value_name = 19; if x == 10 { - //~^ ERROR: all if blocks contain the same code at the start let used_value_name = "Different type"; println!("Str: {}", used_value_name); let _ = 1; @@ -69,6 +68,7 @@ fn simple_but_suggestion_is_invalid() { println!("Str: {}", used_value_name); let _ = 2; } + //~^^^^^^^^^ ERROR: all if blocks contain the same code at the start let _ = used_value_name; // This can be automatically moved as `can_be_overridden` is not used again @@ -101,11 +101,11 @@ fn check_if_same_than_else_mask() { } if x == 2019 { - //~^ ERROR: this `if` has identical blocks println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } else { println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } + //~^^^^^ ERROR: this `if` has identical blocks } #[allow(clippy::vec_init_then_push)] diff --git a/tests/ui/branches_sharing_code/shared_at_top.stderr b/tests/ui/branches_sharing_code/shared_at_top.stderr index 9d4d42fb689e..317d1577226c 100644 --- a/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -2,7 +2,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:11:5 | LL | / if true { -LL | | LL | | println!("Hello World!"); | |_________________________________^ | @@ -21,7 +20,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:21:5 | LL | / if x == 0 { -LL | | LL | | let y = 9; LL | | println!("The value y was set to: `{}`", y); LL | | let _z = y; @@ -54,7 +52,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:62:5 | LL | / if x == 10 { -LL | | LL | | let used_value_name = "Different type"; LL | | println!("Str: {}", used_value_name); | |_____________________________________________^ @@ -105,13 +102,12 @@ error: this `if` has identical blocks | LL | if x == 2019 { | __________________^ -LL | | LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } else { | |_____^ | note: same as this - --> $DIR/shared_at_top.rs:106:12 + --> $DIR/shared_at_top.rs:105:12 | LL | } else { | ____________^ diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.rs b/tests/ui/branches_sharing_code/valid_if_blocks.rs index 2aeacb89c0cb..b63819d7c393 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.rs +++ b/tests/ui/branches_sharing_code/valid_if_blocks.rs @@ -107,9 +107,9 @@ fn valid_examples() { // Let's test empty blocks if false { - //~^ ERROR: this `if` has identical blocks } else { } + //~^^^ ERROR: this `if` has identical blocks } /// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint @@ -119,7 +119,6 @@ fn trigger_other_lint() { // Same block if x == 0 { - //~^ ERROR: this `if` has identical blocks let u = 19; println!("How are u today?"); let _ = "This is a string"; @@ -128,6 +127,7 @@ fn trigger_other_lint() { println!("How are u today?"); let _ = "This is a string"; } + //~^^^^^^^^^ ERROR: this `if` has identical blocks // Only same expression let _ = if x == 6 { 7 } else { 7 }; @@ -138,28 +138,24 @@ fn trigger_other_lint() { println!("Well I'm the most important block"); "I'm a pretty string" } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below if y == 90 { "=^.^=" } else { ":D" } } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); if y == 90 { "=^.^=" } else { ":D" } }; + //~^^^^^^^^^ ERROR: this `if` has identical blocks if x == 0 { println!("I'm single"); } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); } + //~^^^^^ ERROR: this `if` has identical blocks } fn main() {} diff --git a/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/tests/ui/branches_sharing_code/valid_if_blocks.stderr index fcbf12235aa1..0daf2ff6967c 100644 --- a/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -3,12 +3,11 @@ error: this `if` has identical blocks | LL | if false { | ______________^ -LL | | LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:111:12 + --> $DIR/valid_if_blocks.rs:110:12 | LL | } else { | ____________^ @@ -25,7 +24,6 @@ error: this `if` has identical blocks | LL | if x == 0 { | _______________^ -LL | | LL | | let u = 19; LL | | println!("How are u today?"); LL | | let _ = "This is a string"; @@ -33,7 +31,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:126:12 + --> $DIR/valid_if_blocks.rs:125:12 | LL | } else { | ____________^ @@ -60,20 +58,17 @@ error: this `if` has identical blocks | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:146:12 + --> $DIR/valid_if_blocks.rs:144:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } @@ -81,22 +76,19 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:155:23 + --> $DIR/valid_if_blocks.rs:153:23 | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:159:12 + --> $DIR/valid_if_blocks.rs:155:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | } | |_____^ diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index e84b20e9fef0..d53e1383d845 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -21,7 +21,6 @@ fn foo() -> bool { fn if_same_then_else() { if true { - //~^ ERROR: this `if` has identical blocks Foo { bar: 42 }; 0..10; ..; @@ -38,6 +37,7 @@ fn if_same_then_else() { 0..=10; foo(); } + //~^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { Foo { bar: 42 }; @@ -64,19 +64,11 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 0.0 - } else { - 0.0 - }; + let _ = if true { 0.0 } else { 0.0 }; + //~^ ERROR: this `if` has identical blocks - let _ = if true { - //~^ ERROR: this `if` has identical blocks - -0.0 - } else { - -0.0 - }; + let _ = if true { -0.0 } else { -0.0 }; + //~^ ERROR: this `if` has identical blocks let _ = if true { 0.0 } else { -0.0 }; @@ -87,15 +79,10 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 42 - } else { - 42 - }; + let _ = if true { 42 } else { 42 }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks let bar = if true { 42 } else { 43 }; while foo() { @@ -110,6 +97,7 @@ fn if_same_then_else() { } bar + 1; } + //~^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { let _ = match 42 { diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index fb33e94e6c3d..281f30f88b46 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:32:12 + --> $DIR/if_same_then_else.rs:31:12 | LL | } else { | ____________^ @@ -29,75 +29,54 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:70:12 + --> $DIR/if_same_then_else.rs:67:34 | -LL | } else { - | ____________^ -LL | | 0.0 -LL | | }; - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:74:21 + --> $DIR/if_same_then_else.rs:70:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | -0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:77:12 + --> $DIR/if_same_then_else.rs:70:35 | -LL | } else { - | ____________^ -LL | | -0.0 -LL | | }; - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:90:21 + --> $DIR/if_same_then_else.rs:82:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 42 -LL | | } else { - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:93:12 + --> $DIR/if_same_then_else.rs:82:33 | -LL | } else { - | ____________^ -LL | | 42 -LL | | }; - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:97:13 + --> $DIR/if_same_then_else.rs:85:13 | LL | if true { | _____________^ -LL | | LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:105:12 + --> $DIR/if_same_then_else.rs:92:12 | LL | } else { | ____________^ @@ -110,7 +89,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:250:14 + --> $DIR/if_same_then_else.rs:238:14 | LL | if x { | ______________^ @@ -119,7 +98,7 @@ LL | | } else { | |_________^ | note: same as this - --> $DIR/if_same_then_else.rs:252:16 + --> $DIR/if_same_then_else.rs:240:16 | LL | } else { | ________________^ diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 0b171f21d0cc..e23c77b08274 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -13,7 +13,6 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { - //~^ ERROR: this `if` has identical blocks for _ in &[42] { let foo: &Option<_> = &Some::(42); if foo.is_some() { @@ -32,20 +31,21 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } + //~^^^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let Some(a) = Some(42) {} } else { if let Some(a) = Some(42) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let (1, .., 3) = (1, 2, 3) {} } else { if let (1, .., 3) = (1, 2, 3) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { if let (1, .., 3) = (1, 2, 3) {} @@ -90,19 +90,15 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } // Same NaNs - let _ = if true { - //~^ ERROR: this `if` has identical blocks - f32::NAN - } else { - f32::NAN - }; + let _ = if true { f32::NAN } else { f32::NAN }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks Ok("foo")?; } else { Ok("foo")?; } + //~^^^^^ ERROR: this `if` has identical blocks if true { let foo = ""; @@ -122,13 +118,13 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = "bar"; return Ok(&foo[0..]); } else if true { - //~^ ERROR: this `if` has identical blocks let foo = ""; return Ok(&foo[0..]); } else { let foo = ""; return Ok(&foo[0..]); } + //~^^^^^^^ ERROR: this `if` has identical blocks // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559. if true { diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index fe68ef2711b5..4e7a7c87dc54 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::(42); +LL | | if foo.is_some() { ... | LL | | } LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:25:12 + --> $DIR/if_same_then_else2.rs:24:12 | LL | } else { | ____________^ @@ -31,13 +31,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:39:12 + --> $DIR/if_same_then_else2.rs:38:12 | LL | } else { | ____________^ @@ -50,13 +49,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:46:12 + --> $DIR/if_same_then_else2.rs:45:12 | LL | } else { | ____________^ @@ -67,34 +65,26 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:93:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | f32::NAN -LL | | } else { - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else2.rs:96:12 + --> $DIR/if_same_then_else2.rs:93:39 | -LL | } else { - | ____________^ -LL | | f32::NAN -LL | | }; - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:100:13 + --> $DIR/if_same_then_else2.rs:96:13 | LL | if true { | _____________^ -LL | | LL | | Ok("foo")?; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:103:12 + --> $DIR/if_same_then_else2.rs:98:12 | LL | } else { | ____________^ @@ -103,18 +93,17 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:124:20 + --> $DIR/if_same_then_else2.rs:120:20 | LL | } else if true { | ____________________^ -LL | | LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:128:12 + --> $DIR/if_same_then_else2.rs:123:12 | LL | } else { | ____________^ diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 525a355f4035..3428ff459060 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -13,7 +13,6 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { 42 => { - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm foo(); let mut a = 42 + [23].len() as i32; if true { @@ -32,6 +31,7 @@ fn match_same_arms() { a }, }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { 42 => foo(), @@ -146,13 +146,13 @@ fn match_same_arms() { empty!(0); }, 1 => { - //~^ ERROR: this match arm has an identical body to another arm empty!(0); }, x => { empty!(x); }, } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 40b20c7e16d2..512ca7413a79 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -2,9 +2,9 @@ error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { -LL | | LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; +LL | | if true { ... | LL | | a LL | | }, @@ -12,7 +12,7 @@ LL | | }, | = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:25:9 + --> $DIR/match_same_arms2.rs:24:9 | LL | / _ => { LL | | foo(); @@ -122,7 +122,6 @@ LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` | _________| | | -LL | | LL | | empty!(0); LL | | }, | |_________^ From c427754b52415a1fb11c83aa278b5fec21146b27 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 2 Jan 2024 20:39:31 +0000 Subject: [PATCH 019/251] Add platform support matrix Fixes rust-lang/rustc_codegen_cranelift#1441 --- Readme.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Readme.md b/Readme.md index ca6ecdf1d0e8..1c48097da2aa 100644 --- a/Readme.md +++ b/Readme.md @@ -62,6 +62,27 @@ $ ./test.sh For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. +## Platform support + +|OS \ architecture|x86\_64|AArch64|Riscv64|s390x (System-Z)| +|---|---|---|---|---| +|Linux|✅|✅|✅[^no-rustup]|✅[^no-rustup]| +|FreeBSD|✅[^no-rustup]|❓|❓|❓| +|AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| +|Other unixes|❓|❓|❓|❓| +|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|Windows|✅[^no-rustup]|❌|N/A|N/A| + +✅: Fully supported and tested +❓: Maybe supported, not tested +❌: Not supported at all + +Not all targets are available as rustup component for nightly. See notes in the platform support matrix. + +[^xcoff]: XCOFF object file format is not supported. +[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). +[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. + ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. From 45d8c121ba02c825379b655d8dd74e1843e98d62 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:17:00 +0000 Subject: [PATCH 020/251] Return architecturally mandated target features to rustc In the future the actual target features that Cranelift enables should be returned here, but for now this works. Fixes rust-lang/rustc_codegen_cranelift#1438 --- src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b482f0dd2f0a..f327577eb4d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; pub use crate::config::*; use crate::prelude::*; @@ -190,8 +190,17 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] // FIXME necessary for #[cfg(target_feature] + fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec { + // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] + if sess.target.arch == "x86_64" && sess.target.os != "none" { + // x86_64 mandates SSE2 support + vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")] + } else if sess.target.arch == "aarch64" && sess.target.os != "none" { + // AArch64 mandates Neon support + vec![sym::neon] + } else { + vec![] + } } fn print_version(&self) { From 3b8794edf4b930c3de435cdc436f00e7b9e72cf8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:08:32 +0000 Subject: [PATCH 021/251] Fix xmm operands in inline assembly --- src/inline_asm.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 6b9cec39d702..1d0d7ee75de2 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -506,10 +506,34 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push('%'); } - self.registers[*operand_idx] - .unwrap() - .emit(&mut generated_asm, self.arch, *modifier) - .unwrap(); + + let reg = self.registers[*operand_idx].unwrap(); + match self.arch { + InlineAsmArch::X86_64 => match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + let class = match *modifier { + None | Some('x') => "xmm", + Some('y') => "ymm", + Some('z') => "zmm", + _ => unreachable!(), + }; + write!( + generated_asm, + "{class}{}", + reg as u32 - X86InlineAsmReg::xmm0 as u32 + ) + .unwrap(); + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) + .unwrap(), + }, + _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), + } } CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); From c8f5d35508e062bd2d95e6c03429bfec831db6d3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:18:00 +0100 Subject: [PATCH 022/251] Restructure x86 signed pack instructions This reduces the amount of duplicated code and the chance for bugs. I validated the new code for correctness against LLVM using the following script. It found many bugs in the implementation until I was finally able to get it correct and passing. ```rust //! Test for x86 pack instructions. Prints deterministic results, use it to compare backends. use std::arch::x86_64::{self, __m128i, __m256i}; use rand::{rngs::SmallRng, Rng, SeedableRng}; fn main() { let rng = &mut SmallRng::seed_from_u64(123); for _ in 0..100_000 { unsafe { sse_test(rng); avx_test(rng); } } } unsafe fn sse_test(rng: &mut SmallRng) { print_sse_8(x86_64::_mm_packus_epi16(sse16(rng), sse16(rng))); print_sse_8(x86_64::_mm_packs_epi16(sse16(rng), sse16(rng))); print_sse_16(x86_64::_mm_packus_epi32(sse32(rng), sse32(rng))); print_sse_16(x86_64::_mm_packs_epi32(sse32(rng), sse32(rng))); } unsafe fn avx_test(rng: &mut SmallRng) { print_avx_8(x86_64::_mm256_packs_epi16(avx16(rng), avx16(rng))); print_avx_8(x86_64::_mm256_packs_epi16(avx16(rng), avx16(rng))); print_avx_16(x86_64::_mm256_packus_epi32(avx32(rng), avx32(rng))); print_avx_16(x86_64::_mm256_packs_epi32(avx32(rng), avx32(rng))); } fn print_sse_8(t: __m128i) { let ints = unsafe { std::mem::transmute::<_, [i8; 16]>(t) }; println!("{ints:?}"); } fn print_sse_16(t: __m128i) { let ints = unsafe { std::mem::transmute::<_, [i16; 8]>(t) }; println!("{ints:?}"); } fn print_avx_8(t: __m256i) { let ints = unsafe { std::mem::transmute::<_, [i8; 32]>(t) }; println!("{ints:?}"); } fn print_avx_16(t: __m256i) { let ints = unsafe { std::mem::transmute::<_, [i16; 16]>(t) }; println!("{ints:?}"); } fn sse16(rand: &mut SmallRng) -> __m128i { unsafe { std::mem::transmute([(); 8].map(|()| i16(rand))) } } fn sse32(rand: &mut SmallRng) -> __m128i { unsafe { std::mem::transmute([(); 4].map(|()| i32(rand))) } } fn avx16(rand: &mut SmallRng) -> __m256i { unsafe { std::mem::transmute([(); 16].map(|()| i16(rand))) } } fn avx32(rand: &mut SmallRng) -> __m256i { unsafe { std::mem::transmute([(); 8].map(|()| i32(rand))) } } fn i16(rand: &mut SmallRng) -> i16 { if rand.gen() { rand.gen::() } else { rand.gen::() as i16 } } fn i32(rand: &mut SmallRng) -> i32 { if rand.gen() { rand.gen::() } else { rand.gen::() as i32 } } ``` --- src/intrinsics/llvm_x86.rs | 328 +++++++++++++++---------------------- 1 file changed, 132 insertions(+), 196 deletions(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 81114cbf40d8..445622fc539b 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -610,230 +610,56 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi16&ig_expand=4903 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Sse); + } - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); + "llvm.x86.sse2.packsswb.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi16&ig_expand=4848 + intrinsic_args!(fx, args => (a, b); intrinsic); - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Sse); } "llvm.x86.avx2.packuswb" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi16&ig_expand=4906 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Avx); } - "llvm.x86.sse2.packssdw.128" => { - // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + "llvm.x86.avx2.packsswb" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi16&ig_expand=4851 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Avx); } "llvm.x86.sse41.packusdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi32&ig_expand=4912 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Sse); + } - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.u16); - assert_eq!(lane_count * 2, ret_lane_count); + "llvm.x86.sse2.packssdw.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + intrinsic_args!(fx, args => (a, b); intrinsic); - let min_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MIN)); - let max_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MAX)); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u16); + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.avx2.packusdw" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi32&ig_expand=4883 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Avx); } "llvm.x86.avx2.packssdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi32&ig_expand=4892 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx); } "llvm.x86.fma.vfmaddsub.ps" @@ -1407,3 +1233,113 @@ fn llvm_add_sub<'tcx>( (cb_out, c) } + +enum PackSize { + U8, + U16, + S8, + S16, +} + +impl PackSize { + fn ret_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I8, + Self::U16 | Self::S16 => types::I16, + } + } + fn src_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I16, + Self::U16 | Self::S16 => types::I32, + } + } + fn src_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 | Self::S8 => tcx.types.i16, + Self::U16 | Self::S16 => tcx.types.i32, + } + } + fn ret_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 => tcx.types.u8, + Self::S8 => tcx.types.i8, + Self::U16 => tcx.types.u16, + Self::S16 => tcx.types.i16, + } + } + fn max(&self) -> i64 { + match self { + Self::U8 => u8::MAX as u64 as i64, + Self::S8 => i8::MAX as u8 as u64 as i64, + Self::U16 => u16::MAX as u64 as i64, + Self::S16 => i16::MAX as u64 as u64 as i64, + } + } + fn min(&self) -> i64 { + match self { + Self::U8 | Self::U16 => 0, + Self::S8 => i16::from(i8::MIN) as u16 as i64, + Self::S16 => i32::from(i16::MIN) as u32 as i64, + } + } +} + +enum PackWidth { + Sse = 1, + Avx = 2, +} +impl PackWidth { + fn divisor(&self) -> u64 { + match self { + Self::Sse => 1, + Self::Avx => 2, + } + } +} + +fn pack_instruction<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + a: CValue<'tcx>, + b: CValue<'tcx>, + ret: CPlace<'tcx>, + ret_size: PackSize, + width: PackWidth, +) { + assert_eq!(a.layout(), b.layout()); + let layout = a.layout(); + + let (src_lane_count, src_lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(src_lane_ty, ret_size.src_ty(fx.tcx)); + assert_eq!(ret_lane_ty, ret_size.ret_ty(fx.tcx)); + assert_eq!(src_lane_count * 2, ret_lane_count); + + let min = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.min()); + let max = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.max()); + let ret_lane_layout = fx.layout_of(ret_size.ret_ty(fx.tcx)); + + let mut round = |source: CValue<'tcx>, source_offset: u64, dest_offset: u64| { + let step_amount = src_lane_count / width.divisor(); + let dest_offset = step_amount * dest_offset; + for idx in 0..step_amount { + let lane = source.value_lane(fx, step_amount * source_offset + idx).load_scalar(fx); + let sat = fx.bcx.ins().smax(lane, min); + let sat = match ret_size { + PackSize::U8 | PackSize::U16 => fx.bcx.ins().umin(sat, max), + PackSize::S8 | PackSize::S16 => fx.bcx.ins().smin(sat, max), + }; + let res = fx.bcx.ins().ireduce(ret_size.ret_clif_type(), sat); + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, dest_offset + idx).write_cvalue(fx, res_lane); + } + }; + + round(a, 0, 0); + round(b, 0, 1); + + if let PackWidth::Avx = width { + round(a, 1, 2); + round(b, 1, 3); + } +} From 22019dbac879ae899c1ab13ad48503af28c3802b Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 3 Jan 2024 20:28:08 +0100 Subject: [PATCH 023/251] Mention correctness test --- src/intrinsics/llvm_x86.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 445622fc539b..24a5df1630de 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1298,6 +1298,8 @@ impl PackWidth { } } +/// Implement an x86 pack instruction with the intrinsic `_mm{,256}pack{us,s}_epi{16,32}`. +/// Validated for correctness against LLVM, see commit `c8f5d35508e062bd2d95e6c03429bfec831db6d3`. fn pack_instruction<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, a: CValue<'tcx>, From 6fea128f8c859a3f63e6ca684083419ca00d58d3 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 3 Jan 2024 21:23:55 +0100 Subject: [PATCH 024/251] Use `rust-analyzer.rustc.source` to get r-a working with rustc --- .vscode/settings.json | 3 ++- Readme.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 834a1362caf3..491646ce59bb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,9 @@ { "editor.formatOnSave": true, - // source for rustc_* is not included in the rust-src component; disable the errors about this + // in case rustc.source is disabled for performance reasons; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", diff --git a/Readme.md b/Readme.md index 1c48097da2aa..4f4552619639 100644 --- a/Readme.md +++ b/Readme.md @@ -121,6 +121,8 @@ You need to do this steps to successfully compile and use the cranelift backend * (Optional) run tests: `rustup run stage2 ./y.sh test` 8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. +You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all From c824399d74feee7f00e4b8d75f9dd85c633193f9 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 4 Jan 2024 13:08:38 -0800 Subject: [PATCH 025/251] Fix broken markdown in csky-unknown-linux-gnuabiv2.md --- .../rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index a54abcb606ea..e72bfb8bae76 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -50,6 +50,7 @@ cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" [target.csky-unknown-linux-gnuabiv2hf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" +``` ### Build From 74987d04fc3f8b85be2cdbdddc3ea3e1e09a6ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 5 Jan 2024 22:40:25 +0100 Subject: [PATCH 026/251] fix a couple of clippy warnings --- src/driver/aot.rs | 2 +- src/inline_asm.rs | 4 ++-- src/intrinsics/simd.rs | 4 ++-- src/lib.rs | 7 ++----- src/unsize.rs | 7 +++---- src/vtable.rs | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index e77b0cd0721b..6cfbb52e9218 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -467,7 +467,7 @@ pub(crate) fn run_aot( let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")) + .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) .as_str() .to_string(); diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 1d0d7ee75de2..7793b1b70924 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -52,7 +52,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( } let operands = operands - .into_iter() + .iter() .map(|operand| match *operand { InlineAsmOperand::In { reg, ref value } => CInlineAsmOperand::In { reg, @@ -763,7 +763,7 @@ fn call_inline_asm<'tcx>( }, ) .unwrap(); - let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); + let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(inline_asm_func, asm_name); } diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 78ea7c2dbfc3..59dfba31a0a4 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -293,7 +293,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } ret.write_cvalue(fx, base); - let ret_lane = ret.place_lane(fx, idx.try_into().unwrap()); + let ret_lane = ret.place_lane(fx, idx.into()); ret_lane.write_cvalue(fx, val); } @@ -340,7 +340,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); } - let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); + let ret_lane = v.value_lane(fx, idx.into()); ret.write_cvalue(fx, ret_lane); } diff --git a/src/lib.rs b/src/lib.rs index f327577eb4d3..635ff0ba7097 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,16 +314,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { - let builder = cranelift_native::builder_with_options(true).unwrap(); - builder - } + Some("native") => cranelift_native::builder_with_options(true).unwrap(), Some(value) => { let mut builder = cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| { sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err)); }); - if let Err(_) = builder.enable(value) { + if builder.enable(value).is_err() { sess.dcx() .fatal("the specified target cpu isn't currently supported by Cranelift."); } diff --git a/src/unsize.rs b/src/unsize.rs index f777e11371f1..acfa461a6f30 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -28,10 +28,9 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - ( - &ty::Dynamic(ref data_a, _, src_dyn_kind), - &ty::Dynamic(ref data_b, _, target_dyn_kind), - ) if src_dyn_kind == target_dyn_kind => { + (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) + if src_dyn_kind == target_dyn_kind => + { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { diff --git a/src/vtable.rs b/src/vtable.rs index 41ea0b122de7..d2254d4c15e6 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -95,7 +95,7 @@ pub(crate) fn get_vtable<'tcx>( let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); let data_id = data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id)); } From 853504df238835208d8a565cbb532918d84492c6 Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Fri, 5 Jan 2024 22:34:43 +0000 Subject: [PATCH 027/251] Remove feature not required by `Ipv6Addr::to_cononical` doctest The feature does not seem to be required by this doctest. --- library/core/src/net/ip_addr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 1ef876a3163c..762d1caad4b3 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1860,7 +1860,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); From 837c0305c6e61c1591b0c59935bb71df11b3638e Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Fri, 22 Dec 2023 15:12:01 +0300 Subject: [PATCH 028/251] Update test for `E0796` and `static_mut_ref` lint --- example/mini_core_hello_world.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index a1cdf31c68a0..2a7b1107ffca 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; unsafe fn zeroed() -> T { From e6570dccccd85f5bfc8497bbd4db615f1d2fdbd2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 3 Jan 2024 17:03:10 +1100 Subject: [PATCH 029/251] Use chaining for `DiagnosticBuilder` construction and `emit`. To avoid the use of a mutable local variable, and because it reads more nicely. --- src/driver/jit.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index a8d8fb189e2e..50d9f287e74c 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -321,9 +321,10 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); - err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - err.emit(); + sess.dcx() + .struct_err(format!("Can't load static lib {}", name)) + .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") + .emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); From 2b3cd46832d99218576b5d01c910a64a4330b542 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Wed, 29 Nov 2023 12:49:48 +0700 Subject: [PATCH 030/251] Improved support of collapse_debuginfo attribute for macros. --- src/debuginfo/line_info.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index 6230ca15d6e1..d1b21d0a0b6c 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -68,15 +68,7 @@ impl DebugContext { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site (when the macro is // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = if tcx.should_collapse_debuginfo(span) { - span - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - rustc_span::hygiene::walk_chain(span, function_span.ctxt()) - }; - + let span = tcx.collapsed_debuginfo(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines()[line]; From 6dd0772707eb50a8129eb0a748cd9ef3de6a754a Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Fri, 22 Dec 2023 21:56:58 -0800 Subject: [PATCH 031/251] Emit suggestion when trying to write exclusive ranges as `..<` --- .../rustc_parse/src/parser/diagnostics.rs | 25 ++++++++-- compiler/rustc_parse/src/parser/expr.rs | 10 +++- tests/ui/parser/range-exclusive-dotdotlt.rs | 43 +++++++++++++++++ .../ui/parser/range-exclusive-dotdotlt.stderr | 46 +++++++++++++++++++ 4 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 tests/ui/parser/range-exclusive-dotdotlt.rs create mode 100644 tests/ui/parser/range-exclusive-dotdotlt.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a9cf26d991c7..dc7a4d5aa383 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -23,7 +23,7 @@ use crate::parser; use crate::parser::attr::InnerAttrPolicy; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; +use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -448,12 +448,11 @@ impl<'a> Parser<'a> { }) } - let mut expected = edible + self.expected_tokens.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token)); + let mut expected = self + .expected_tokens .iter() - .chain(inedible) .cloned() - .map(TokenType::Token) - .chain(self.expected_tokens.iter().cloned()) .filter(|token| { // Filter out suggestions that suggest the same token which was found and deemed incorrect. fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool { @@ -2927,6 +2926,22 @@ impl<'a> Parser<'a> { Ok(()) } + /// Check for exclusive ranges written as `..<` + pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> { + if maybe_lt == token::Lt + && (self.expected_tokens.contains(&TokenType::Token(token::Gt)) + || matches!(self.token.kind, token::Literal(..))) + { + err.span_suggestion( + maybe_lt.span, + "remove the `<` to write an exclusive range", + "", + Applicability::MachineApplicable, + ); + } + err + } + pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool { (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind)) && self.look_ahead(3, |tok| tok == short_kind) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index db777266b59d..7f4d26b370f1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -483,7 +483,11 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?) + let maybe_lt = self.token.clone(); + Some( + self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed) + .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?, + ) } else { None }; @@ -532,11 +536,13 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { let lo = this.token.span; + let maybe_lt = this.look_ahead(1, |t| t.clone()); this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) - .map(|x| (lo.to(x.span), Some(x)))? + .map(|x| (lo.to(x.span), Some(x))) + .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? } else { (lo, None) }; diff --git a/tests/ui/parser/range-exclusive-dotdotlt.rs b/tests/ui/parser/range-exclusive-dotdotlt.rs new file mode 100644 index 000000000000..5752566026f0 --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.rs @@ -0,0 +1,43 @@ +fn foo() { + let _ = 0..<10; + //~^ ERROR: expected type, found `10` + //~| HELP: remove the `<` to write an exclusive range +} + +fn bar() { + let _ = 0..`, or `as`, found `;` + //~| HELP: remove the `<` to write an exclusive range +} + +fn baz() { + let _ = ; + //~^ ERROR: expected `::`, found `;` +} + +fn qux() { + let _ = [1, 2, 3][..<1]; + //~^ ERROR: expected type, found `1` + //~| HELP: remove the `<` to write an exclusive range +} + +fn quux() { + let _ = [1, 2, 3][..`, or `as`, found `]` + //~| HELP: remove the `<` to write an exclusive range +} + +fn foobar() { + let _ = [1, 2, 3][..]; + //~^ ERROR: expected `::`, found `]` +} + +fn ok1() { + let _ = [1, 2, 3][..::default()]; +} + +fn ok2() { + let _ = 0..::default(); +} + +fn main() {} diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr new file mode 100644 index 000000000000..af25e1df343d --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr @@ -0,0 +1,46 @@ +error: expected type, found `10` + --> $DIR/range-exclusive-dotdotlt.rs:2:17 + | +LL | let _ = 0..<10; + | -^^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` + --> $DIR/range-exclusive-dotdotlt.rs:8:20 + | +LL | let _ = 0.. $DIR/range-exclusive-dotdotlt.rs:14:18 + | +LL | let _ = ; + | ^ expected `::` + +error: expected type, found `1` + --> $DIR/range-exclusive-dotdotlt.rs:19:26 + | +LL | let _ = [1, 2, 3][..<1]; + | -^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` + --> $DIR/range-exclusive-dotdotlt.rs:25:29 + | +LL | let _ = [1, 2, 3][.. $DIR/range-exclusive-dotdotlt.rs:31:30 + | +LL | let _ = [1, 2, 3][..]; + | ^ expected `::` + +error: aborting due to 6 previous errors + From c2d071c11c008b08d841d30bae40f8acfdac0c6e Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 9 Jan 2024 06:50:17 -0800 Subject: [PATCH 032/251] Documentation edits for arc_with_non_send_sync Arc's documentation uses the term "thread", aligning to that terminology. Fix typo in "Rc". --- clippy_lints/src/arc_with_non_send_sync.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 657d52d0e9e1..58738d528788 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// `Arc` is an Atomic `RC` and guarantees that updates to the reference counter are - /// Atomic. This is useful in multiprocessing scenarios. To send an `Arc` across processes + /// `Arc` is an Atomic `Rc` and guarantees that updates to the reference counter are + /// Atomic. This is useful in multithreading scenarios. To send an `Arc` across threads /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// From 0dc13d7acb0118d6c14a9209d921e5278e829458 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:16:09 +0100 Subject: [PATCH 033/251] Implement _mm_prefetch as nop --- src/intrinsics/llvm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index a38a728c926d..9c686eba5e03 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -35,6 +35,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( } match intrinsic { + "llvm.prefetch" => { + // Nothing to do. This is merely a perf hint. + } + _ if intrinsic.starts_with("llvm.ctlz.v") => { intrinsic_args!(fx, args => (a); intrinsic); From 281ceb2bd2b2dd5f6ac201f585a2de2d21a41250 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 10:26:18 +0100 Subject: [PATCH 034/251] Document the struct and a few methods --- compiler/rustc_index/src/vec.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 66c5cc774b22..3148b054790f 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -12,10 +12,26 @@ use std::vec; use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. +/// Its purpose is to avoid mixing indexes. /// /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// +/// This allows to index the IndexVec with the new index type: +/// +/// ``` +/// use crate as rustc_index; +/// use rustc_index::{IndexVec, newtype_index}; +/// +/// newtype_index! { +/// pub struct MyIdx {} +/// } +/// +/// let my_index_vec: IndexVec = IndexVec::from_raw(vec![0,1,2,3]); +/// let idx: MyIdx = MyIdx::from_u32(2); +/// assert_eq!(my_index_vec[idx], 2); +/// ``` +/// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -25,11 +41,13 @@ pub struct IndexVec { } impl IndexVec { + /// Constructs a new, empty `IndexVec`. #[inline] pub const fn new() -> Self { IndexVec::from_raw(Vec::new()) } + /// Constructs a new `IndexVec` from a `Vec` #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } @@ -59,6 +77,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } + /// Creates a new `IndexVec` with n copies of `elem` #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where From 1bf3aee3811b92d5833154fd35b98159a233b938 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 11:17:46 +0100 Subject: [PATCH 035/251] Oh well --- compiler/rustc_index/src/vec.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 3148b054790f..3c66e6dde1c2 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -17,27 +17,15 @@ use crate::{Idx, IndexSlice}; /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// -/// This allows to index the IndexVec with the new index type: +/// This allows to index the IndexVec with the new index type /// -/// ``` -/// use crate as rustc_index; -/// use rustc_index::{IndexVec, newtype_index}; -/// -/// newtype_index! { -/// pub struct MyIdx {} -/// } -/// -/// let my_index_vec: IndexVec = IndexVec::from_raw(vec![0,1,2,3]); -/// let idx: MyIdx = MyIdx::from_u32(2); -/// assert_eq!(my_index_vec[idx], 2); -/// ``` /// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, - _marker: PhantomData, + _marker: PhantomData, } impl IndexVec { @@ -77,7 +65,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } - /// Creates a new `IndexVec` with n copies of `elem` + /// Creates a new IndexVec #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where From c8875309b8865b0fc119da4ba795dae129532bc1 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:12:01 +0200 Subject: [PATCH 036/251] deps: deduplicate the version of libloading used The changelog can be found here: https://docs.rs/libloading/latest/libloading/changelog/r0_8_0/index.html --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fdac789423c9..c57e964168f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.7.3", optional = true } +libloading = { version = "0.8.0", optional = true } smallvec = "1.8.1" [patch.crates-io] From be1b86fef43a7cf6c57a2848be02e0dca4738ef1 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 10 Jan 2024 17:13:03 +0200 Subject: [PATCH 037/251] Format sources into the error message when loading codegen backends cc https://github.com/rust-lang/rustc_codegen_cranelift/issues/1447 --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74e7afee7bcb..6d6a1200f502 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,12 +246,12 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys", ] [[package]] From ee8510e4e13e723639e904cdc218e6f3013f0bb4 Mon Sep 17 00:00:00 2001 From: ardi Date: Wed, 10 Jan 2024 18:28:42 +0100 Subject: [PATCH 038/251] Fix some mistakes + new doc --- compiler/rustc_index/src/vec.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 3c66e6dde1c2..73265eb89961 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -17,15 +17,13 @@ use crate::{Idx, IndexSlice}; /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// -/// This allows to index the IndexVec with the new index type -/// -/// +/// This allows to index the IndexVec with the new index type. /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, - _marker: PhantomData, + _marker: PhantomData, } impl IndexVec { @@ -35,7 +33,7 @@ impl IndexVec { IndexVec::from_raw(Vec::new()) } - /// Constructs a new `IndexVec` from a `Vec` + /// Constructs a new `IndexVec` from a `Vec`. #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } @@ -65,7 +63,7 @@ impl IndexVec { IndexVec::from_raw(vec![elem; universe.len()]) } - /// Creates a new IndexVec + /// Creates a new IndexVec with n copies of the `elem`. #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where @@ -92,6 +90,7 @@ impl IndexVec { IndexSlice::from_raw_mut(&mut self.raw) } + /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); From 7c389acd277eada4d2e0856707361cce24c9b23f Mon Sep 17 00:00:00 2001 From: cocodery Date: Thu, 11 Jan 2024 14:52:03 +0800 Subject: [PATCH 039/251] Fix error warning span for issue12045 --- clippy_lints/src/no_effect.rs | 2 +- tests/ui/no_effect.stderr | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 6bbe427ea298..2a2c2b331ba7 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -155,7 +155,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { cx, NO_EFFECT_UNDERSCORE_BINDING, init.hir_id, - stmt.span, + ident.span, "binding to `_` prefixed variable with no side-effect", ); return true; diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index f5ba234b4cbf..8140ba1feee9 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -152,31 +152,31 @@ LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:175:5 + --> $DIR/no_effect.rs:175:9 | LL | let _unused = 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:178:5 + --> $DIR/no_effect.rs:178:9 | LL | let _penguin = || println!("Some helpful closure"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:180:5 + --> $DIR/no_effect.rs:180:9 | LL | let _duck = Struct { field: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:182:5 + --> $DIR/no_effect.rs:182:9 | LL | let _cat = [2, 4, 6, 8][2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 29 previous errors From fb83ef649587413c4e3a8ec9e364b828ec250a56 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 11 Jan 2024 14:22:44 +1100 Subject: [PATCH 040/251] Stop using `DiagnosticBuilder::buffer` in the parser. One consequence is that errors returned by `maybe_new_parser_from_source_str` now must be consumed, so a bunch of places that previously ignored those errors now cancel them. (Most of them explicitly dropped the errors before. I guess that was to indicate "we are explicitly ignoring these", though I'm not 100% sure.) --- clippy_lints/src/doc/needless_doctest_main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index a744b69ecb47..8b018220c171 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -53,7 +53,7 @@ pub fn check( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - drop(errs); + errs.into_iter().for_each(|err| err.cancel()); return (false, test_attr_spans); }, }; From aa220c7ee7a51ab39bccd03ee90fa1c9365a589a Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Jan 2024 17:27:03 +0100 Subject: [PATCH 041/251] Merge commit '26ac6aab023393c94edf42f38f6ad31196009643' --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 10 +- .github/workflows/clippy_dev.yml | 2 +- .github/workflows/deploy.yml | 4 +- .github/workflows/remark.yml | 2 +- CHANGELOG.md | 7 + COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 4 +- book/src/README.md | 2 +- book/src/SUMMARY.md | 1 + .../continuous_integration/github_actions.md | 2 +- book/src/continuous_integration/gitlab.md | 16 + book/src/development/macro_expansions.md | 2 +- book/src/development/type_checking.md | 4 +- book/src/lint_configuration.md | 10 + clippy_config/src/conf.rs | 7 +- clippy_config/src/metadata.rs | 3 + clippy_config/src/msrvs.rs | 2 +- clippy_config/src/types.rs | 6 + clippy_dev/src/new_lint.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 141 ++++-- clippy_lints/src/declared_lints.rs | 8 +- clippy_lints/src/default_numeric_fallback.rs | 41 +- ...ith_brackets.rs => empty_with_brackets.rs} | 56 ++- clippy_lints/src/if_then_some_else_none.rs | 7 +- clippy_lints/src/instant_subtraction.rs | 5 +- clippy_lints/src/item_name_repetitions.rs | 5 + clippy_lints/src/iter_without_into_iter.rs | 9 +- clippy_lints/src/lib.rs | 17 +- clippy_lints/src/lines_filter_map_ok.rs | 3 +- clippy_lints/src/methods/filter_map.rs | 3 +- clippy_lints/src/methods/iter_filter.rs | 208 ++++++--- .../src/methods/manual_is_variant_and.rs | 59 +++ clippy_lints/src/methods/map_clone.rs | 142 ++++-- clippy_lints/src/methods/mod.rs | 115 ++++- .../src/methods/option_as_ref_cloned.rs | 24 + .../src/methods/option_map_unwrap_or.rs | 2 +- .../src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/methods/redundant_as_str.rs | 6 +- clippy_lints/src/methods/str_split.rs | 38 ++ .../src/methods/unnecessary_to_owned.rs | 24 +- clippy_lints/src/methods/useless_asref.rs | 123 +++++- clippy_lints/src/methods/utils.rs | 1 + .../src/missing_asserts_for_indexing.rs | 2 +- .../src/missing_enforced_import_rename.rs | 14 +- clippy_lints/src/mutex_atomic.rs | 26 +- clippy_lints/src/no_effect.rs | 2 +- .../src/non_octal_unix_permissions.rs | 12 +- clippy_lints/src/operators/identity_op.rs | 208 +++++---- clippy_lints/src/pub_underscore_fields.rs | 83 ++++ clippy_lints/src/question_mark.rs | 7 +- clippy_lints/src/serde_api.rs | 2 +- ...ead_local_initializer_can_be_made_const.rs | 102 +++++ clippy_lints/src/transmute/eager_transmute.rs | 53 ++- .../src/transmute/transmute_undefined_repr.rs | 4 +- clippy_lints/src/unconditional_recursion.rs | 413 +++++++++++++++--- .../src/undocumented_unsafe_blocks.rs | 10 +- clippy_lints/src/unit_types/let_unit_value.rs | 21 +- clippy_lints/src/vec.rs | 17 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 13 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 6 +- rust-toolchain | 2 +- rustc_tools_util/README.md | 2 +- .../all_pub_fields/clippy.toml | 1 + .../exported/clippy.toml | 1 + ...ub_underscore_fields.all_pub_fields.stderr | 60 +++ .../pub_underscore_fields.exported.stderr | 12 + .../pub_underscore_fields.rs | 66 +++ .../toml_unknown_key/conf_unknown_key.stderr | 2 + tests/ui/as_conversions.rs | 2 +- tests/ui/cast.rs | 49 +++ tests/ui/cast.stderr | 74 +++- tests/ui/crashes/ice-8821.fixed | 10 - tests/ui/crashes/ice-8821.rs | 2 - tests/ui/crashes/ice-8821.stderr | 11 - tests/ui/default_numeric_fallback_f64.fixed | 4 +- tests/ui/default_numeric_fallback_f64.rs | 2 - tests/ui/default_numeric_fallback_f64.stderr | 26 +- tests/ui/default_numeric_fallback_i32.fixed | 36 +- tests/ui/default_numeric_fallback_i32.rs | 34 +- tests/ui/default_numeric_fallback_i32.stderr | 44 +- tests/ui/eager_transmute.fixed | 35 +- tests/ui/eager_transmute.rs | 35 +- tests/ui/eager_transmute.stderr | 117 ++++- .../empty_enum_variants_with_brackets.fixed | 27 ++ tests/ui/empty_enum_variants_with_brackets.rs | 27 ++ .../empty_enum_variants_with_brackets.stderr | 36 ++ tests/ui/identity_op.fixed | 94 +++- tests/ui/identity_op.rs | 94 +++- tests/ui/identity_op.stderr | 154 +++++-- tests/ui/if_then_some_else_none.rs | 5 + tests/ui/into_iter_without_iter.rs | 39 ++ tests/ui/into_iter_without_iter.stderr | 38 +- tests/ui/iter_filter_is_ok.fixed | 193 +++++++- tests/ui/iter_filter_is_ok.rs | 193 +++++++- tests/ui/iter_filter_is_ok.stderr | 74 +++- tests/ui/iter_filter_is_some.fixed | 231 +++++++++- tests/ui/iter_filter_is_some.rs | 231 +++++++++- tests/ui/iter_filter_is_some.stderr | 62 ++- tests/ui/iter_without_into_iter.rs | 31 ++ tests/ui/iter_without_into_iter.stderr | 40 +- tests/ui/let_unit.fixed | 50 +-- tests/ui/let_unit.rs | 48 +- tests/ui/let_unit.stderr | 56 +-- tests/ui/manual_is_variant_and.fixed | 51 +++ tests/ui/manual_is_variant_and.rs | 57 +++ tests/ui/manual_is_variant_and.stderr | 82 ++++ tests/ui/map_clone.fixed | 24 + tests/ui/map_clone.rs | 24 + tests/ui/map_clone.stderr | 44 +- tests/ui/must_use_candidates.fixed | 6 +- tests/ui/must_use_candidates.rs | 6 +- tests/ui/must_use_candidates.stderr | 10 +- tests/ui/mutex_atomic.rs | 19 +- tests/ui/mutex_atomic.stderr | 30 +- tests/ui/non_octal_unix_permissions.fixed | 4 + tests/ui/non_octal_unix_permissions.rs | 4 + tests/ui/non_octal_unix_permissions.stderr | 2 +- tests/ui/option_as_ref_cloned.fixed | 21 + tests/ui/option_as_ref_cloned.rs | 21 + tests/ui/option_as_ref_cloned.stderr | 37 ++ tests/ui/redundant_as_str.fixed | 2 +- tests/ui/redundant_as_str.rs | 2 +- tests/ui/regex.rs | 2 +- tests/ui/single_char_pattern.fixed | 2 + tests/ui/single_char_pattern.rs | 2 + tests/ui/single_char_pattern.stderr | 26 +- tests/ui/str_split.fixed | 145 ++++++ tests/ui/str_split.rs | 145 ++++++ tests/ui/str_split.stderr | 65 +++ tests/ui/struct_fields.rs | 24 +- tests/ui/struct_fields.stderr | 28 +- ..._local_initializer_can_be_made_const.fixed | 30 ++ ...ead_local_initializer_can_be_made_const.rs | 30 ++ ...local_initializer_can_be_made_const.stderr | 29 ++ tests/ui/unconditional_recursion.rs | 108 ++++- tests/ui/unconditional_recursion.stderr | 95 +++- tests/ui/unnecessary_lazy_eval.fixed | 13 + tests/ui/unnecessary_lazy_eval.rs | 13 + tests/ui/unnecessary_lazy_eval.stderr | 126 +++--- tests/ui/unnecessary_safety_comment.rs | 21 + tests/ui/unnecessary_to_owned_on_split.fixed | 18 +- tests/ui/unnecessary_to_owned_on_split.rs | 18 +- tests/ui/unnecessary_to_owned_on_split.stderr | 24 +- tests/ui/useless_asref.fixed | 14 +- tests/ui/useless_asref.rs | 14 +- tests/ui/useless_asref.stderr | 42 +- tests/ui/useless_conversion.fixed | 4 +- tests/ui/useless_conversion.rs | 4 +- tests/ui/vec.fixed | 7 + tests/ui/vec.rs | 7 + triagebot.toml | 1 - 157 files changed, 5167 insertions(+), 820 deletions(-) create mode 100644 book/src/continuous_integration/gitlab.md rename clippy_lints/src/{empty_structs_with_brackets.rs => empty_with_brackets.rs} (62%) create mode 100644 clippy_lints/src/methods/manual_is_variant_and.rs create mode 100644 clippy_lints/src/methods/option_as_ref_cloned.rs create mode 100644 clippy_lints/src/methods/str_split.rs create mode 100644 clippy_lints/src/pub_underscore_fields.rs create mode 100644 clippy_lints/src/thread_local_initializer_can_be_made_const.rs create mode 100644 tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml create mode 100644 tests/ui-toml/pub_underscore_fields/exported/clippy.toml create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr create mode 100644 tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs delete mode 100644 tests/ui/crashes/ice-8821.fixed delete mode 100644 tests/ui/crashes/ice-8821.stderr create mode 100644 tests/ui/empty_enum_variants_with_brackets.fixed create mode 100644 tests/ui/empty_enum_variants_with_brackets.rs create mode 100644 tests/ui/empty_enum_variants_with_brackets.stderr create mode 100644 tests/ui/manual_is_variant_and.fixed create mode 100644 tests/ui/manual_is_variant_and.rs create mode 100644 tests/ui/manual_is_variant_and.stderr create mode 100644 tests/ui/option_as_ref_cloned.fixed create mode 100644 tests/ui/option_as_ref_cloned.rs create mode 100644 tests/ui/option_as_ref_cloned.stderr create mode 100644 tests/ui/str_split.fixed create mode 100644 tests/ui/str_split.rs create mode 100644 tests/ui/str_split.stderr create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.fixed create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.rs create mode 100644 tests/ui/thread_local_initializer_can_be_made_const.stderr diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 99d80bec0255..5ba960db66dd 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -38,7 +38,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 73c255507428..012797e5ca72 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -26,7 +26,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref }} @@ -72,7 +72,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install i686 dependencies if: matrix.host == 'i686-unknown-linux-gnu' @@ -151,7 +151,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain @@ -175,7 +175,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain @@ -231,7 +231,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index 0f0e3f2db925..37f18a4c0874 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Run - name: Build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 999ee7acfe76..94f494b65c47 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 30bd476332f7..05e1b3b9202b 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index f82421a687b8..4d32bbec914a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5105,6 +5105,7 @@ Released 2018-09-13 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum +[`empty_enum_variants_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum_variants_with_brackets [`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop @@ -5294,6 +5295,7 @@ Released 2018-09-13 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map @@ -5440,6 +5442,7 @@ Released 2018-09-13 [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some +[`option_as_ref_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_cloned [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used @@ -5483,6 +5486,7 @@ Released 2018-09-13 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names +[`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use [`pub_with_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_with_shorthand [`pub_without_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_without_shorthand @@ -5580,6 +5584,7 @@ Released 2018-09-13 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core +[`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign @@ -5612,6 +5617,7 @@ Released 2018-09-13 [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr [`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest [`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module +[`thread_local_initializer_can_be_made_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#thread_local_initializer_can_be_made_const [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args @@ -5810,4 +5816,5 @@ Released 2018-09-13 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items +[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior diff --git a/COPYRIGHT b/COPYRIGHT index 82703b18fd7d..219693d63d97 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 0d62c37278e5..506582c31d6d 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index b724b24aa830..6d8ee9afb616 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2022 The Rust Project Developers +Copyright (c) 2014-2024 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 5d490645d897..fa18447090c1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. @@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2023 The Rust Project Developers +Copyright 2014-2024 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/book/src/README.md b/book/src/README.md index 486ea3df7042..e7972b0db19c 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index b02457307d74..a048fbbd8acf 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -9,6 +9,7 @@ - [Clippy's Lints](lints.md) - [Continuous Integration](continuous_integration/README.md) - [GitHub Actions](continuous_integration/github_actions.md) + - [GitLab CI](continuous_integration/gitlab.md) - [Travis CI](continuous_integration/travis.md) - [Development](development/README.md) - [Basics](development/basics.md) diff --git a/book/src/continuous_integration/github_actions.md b/book/src/continuous_integration/github_actions.md index 339287a7dd95..b588c8f0f02c 100644 --- a/book/src/continuous_integration/github_actions.md +++ b/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/book/src/continuous_integration/gitlab.md b/book/src/continuous_integration/gitlab.md new file mode 100644 index 000000000000..bb3ef246c2fa --- /dev/null +++ b/book/src/continuous_integration/gitlab.md @@ -0,0 +1,16 @@ +# GitLab CI + +You can add Clippy to GitLab CI by using the latest stable [rust docker image](https://hub.docker.com/_/rust), +as it is shown in the `.gitlab-ci.yml` CI configuration file below, + +```yml +# Make sure CI fails on all warnings, including Clippy lints +variables: + RUSTFLAGS: "-Dwarnings" + +clippy_check: + image: rust:latest + script: + - rustup component add clippy + - cargo clippy --all-targets --all-features +``` diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md index c5eb000272d3..aecca9ef72e9 100644 --- a/book/src/development/macro_expansions.md +++ b/book/src/development/macro_expansions.md @@ -102,7 +102,7 @@ let x: Option = Some(42); m!(x, x.unwrap()); ``` -If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded +If the `m!(x, x.unwrap());` line is expanded, we would get two expanded expressions: - `x.is_some()` (from the `$a.is_some()` line in the `m` macro) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index a8c9660da4c8..dc29ab5d08da 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -133,7 +133,7 @@ in this chapter: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type @@ -144,7 +144,7 @@ in this chapter: [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 7c9a8eb1bfba..3b62ae0524ab 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -805,3 +805,13 @@ for _ in &mut *rmvec {} * [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) +## `pub-underscore-fields-behavior` + + +**Default Value:** `"PublicallyExported"` + +--- +**Affected lints:** +* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields) + + diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index a4f368397ced..5477d9b83a72 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,5 +1,5 @@ use crate::msrvs::Msrv; -use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename}; +use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; use rustc_data_structures::fx::FxHashSet; use rustc_session::Session; @@ -547,6 +547,11 @@ define_Conf! { /// /// Whether to also run the listed lints on private items. (check_private_items: bool = false), + /// Lint: PUB_UNDERSCORE_FIELDS + /// + /// Lint "public" fields in a struct that are prefixed with an underscore based on their + /// exported visibility, or whether they are marked as "pub". + (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PublicallyExported), } /// Search for the configuration file. diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs index 2451fbc91e89..3ba2796e18d3 100644 --- a/clippy_config/src/metadata.rs +++ b/clippy_config/src/metadata.rs @@ -96,6 +96,9 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { doc_comment.make_ascii_lowercase(); let lints: Vec = doc_comment .split_off(DOC_START.len()) + .lines() + .next() + .unwrap() .split(", ") .map(str::to_string) .collect(); diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index dae9f09ec00a..72d5b9aff28d 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,7 +17,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } - 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } + 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index df48cc3f5e39..baee09629ac4 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -126,3 +126,9 @@ unimplemented_serialize! { Rename, MacroMatcher, } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum PubUnderscoreFieldsBehaviour { + PublicallyExported, + AllPubFields, +} diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 31a42734c131..5d9cde06cd86 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -67,7 +67,7 @@ pub fn create( if pass == "early" { println!( "\n\ - NOTE: Use a late pass unless you need something specific from\ + NOTE: Use a late pass unless you need something specific from\n\ an early pass, as they lack many features and utilities" ); } diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index bd12ee406284..1df5a25f674d 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,12 +1,14 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{method_chain_args, sext}; -use rustc_hir::{Expr, ExprKind}; +use clippy_utils::{clip, method_chain_args, sext}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, UintTy}; use super::CAST_SIGN_LOSS; +const METHODS_RET_POSITIVE: &[&str] = &["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if should_lint(cx, cast_op, cast_from, cast_to) { span_lint( @@ -25,33 +27,28 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast return false; } - // Don't lint for positive constants. - let const_val = constant(cx, cx.typeck_results(), cast_op); - if let Some(Constant::Int(n)) = const_val - && let ty::Int(ity) = *cast_from.kind() - && sext(cx.tcx, n, ity) >= 0 - { + // Don't lint if `cast_op` is known to be positive. + if let Sign::ZeroOrPositive = expr_sign(cx, cast_op, cast_from) { return false; } - // Don't lint for the result of methods that always return non-negative values. - if let ExprKind::MethodCall(path, ..) = cast_op.kind { - let mut method_name = path.ident.name.as_str(); - let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; - - if method_name == "unwrap" - && let Some(arglist) = method_chain_args(cast_op, &["unwrap"]) - && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind - { - method_name = inner_path.ident.name.as_str(); - } - - if allowed_methods.iter().any(|&name| method_name == name) { - return false; - } + let (mut uncertain_count, mut negative_count) = (0, 0); + // Peel off possible binary expressions, e.g. x * x * y => [x, x, y] + let Some(exprs) = exprs_with_selected_binop_peeled(cast_op) else { + // Assume cast sign lose if we cannot determine the sign of `cast_op` + return true; + }; + for expr in exprs { + let ty = cx.typeck_results().expr_ty(expr); + match expr_sign(cx, expr, ty) { + Sign::Negative => negative_count += 1, + Sign::Uncertain => uncertain_count += 1, + Sign::ZeroOrPositive => (), + }; } - true + // Lint if there are odd number of uncertain or negative results + uncertain_count % 2 == 1 || negative_count % 2 == 1 }, (false, true) => !cast_to.is_signed(), @@ -59,3 +56,97 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast (_, _) => false, } } + +fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Option { + if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)? + && let ty::Int(ity) = *ty.kind() + { + return Some(sext(cx.tcx, n, ity)); + } + None +} + +enum Sign { + ZeroOrPositive, + Negative, + Uncertain, +} + +fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign { + // Try evaluate this expr first to see if it's positive + if let Some(val) = get_const_int_eval(cx, expr, ty) { + return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative }; + } + // Calling on methods that always return non-negative values. + if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { + let mut method_name = path.ident.name.as_str(); + + if method_name == "unwrap" + && let Some(arglist) = method_chain_args(expr, &["unwrap"]) + && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind + { + method_name = inner_path.ident.name.as_str(); + } + + if method_name == "pow" + && let [arg] = args + { + return pow_call_result_sign(cx, caller, arg); + } else if METHODS_RET_POSITIVE.iter().any(|&name| method_name == name) { + return Sign::ZeroOrPositive; + } + } + + Sign::Uncertain +} + +/// Return the sign of the `pow` call's result. +/// +/// If the caller is a positive number, the result is always positive, +/// If the `power_of` is a even number, the result is always positive as well, +/// Otherwise a [`Sign::Uncertain`] will be returned. +fn pow_call_result_sign(cx: &LateContext<'_>, caller: &Expr<'_>, power_of: &Expr<'_>) -> Sign { + let caller_ty = cx.typeck_results().expr_ty(caller); + if let Some(caller_val) = get_const_int_eval(cx, caller, caller_ty) + && caller_val >= 0 + { + return Sign::ZeroOrPositive; + } + + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), power_of) + && clip(cx.tcx, n, UintTy::U32) % 2 == 0 + { + return Sign::ZeroOrPositive; + } + + Sign::Uncertain +} + +/// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`], +/// which the result could always be positive under certain condition. +/// +/// Other operators such as `+`/`-` causing the result's sign hard to determine, which we will +/// return `None` +fn exprs_with_selected_binop_peeled<'a>(expr: &'a Expr<'_>) -> Option>> { + #[inline] + fn collect_operands<'a>(expr: &'a Expr<'a>, operands: &mut Vec<&'a Expr<'a>>) -> Option<()> { + match expr.kind { + ExprKind::Binary(op, lhs, rhs) => { + if matches!(op.node, BinOpKind::Mul | BinOpKind::Div | BinOpKind::Rem) { + collect_operands(lhs, operands); + operands.push(rhs); + } else { + // Things are complicated when there are other binary ops exist, + // abort checking by returning `None` for now. + return None; + } + }, + _ => operands.push(expr), + } + Some(()) + } + + let mut res = vec![]; + collect_operands(expr, &mut res)?; + Some(res) +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index eae9dfac064e..20230106d536 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -150,7 +150,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, crate::empty_drop::EMPTY_DROP_INFO, crate::empty_enum::EMPTY_ENUM_INFO, - crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, + crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO, + crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, crate::endian_bytes::BIG_ENDIAN_BYTES_INFO, crate::endian_bytes::HOST_ENDIAN_BYTES_INFO, crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO, @@ -385,6 +386,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, @@ -408,6 +410,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::NO_EFFECT_REPLACE_INFO, crate::methods::OBFUSCATED_IF_ELSE_INFO, crate::methods::OK_EXPECT_INFO, + crate::methods::OPTION_AS_REF_CLONED_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, crate::methods::OPTION_MAP_OR_ERR_OK_INFO, @@ -433,6 +436,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, + crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, @@ -576,6 +580,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::ptr::MUT_FROM_REF_INFO, crate::ptr::PTR_ARG_INFO, crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO, + crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO, crate::pub_use::PUB_USE_INFO, crate::question_mark::QUESTION_MARK_INFO, crate::question_mark_used::QUESTION_MARK_USED_INFO, @@ -648,6 +653,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, + crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 64a924a776a6..712bc075650f 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -4,7 +4,7 @@ use clippy_utils::{get_parent_node, numeric_literal}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -122,13 +122,42 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { + ExprKind::Block( + Block { + stmts, expr: Some(_), .. + }, + _, + ) => { + if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id) + && let Some(fn_sig) = parent.fn_sig() + && let FnRetTy::Return(_ty) = fn_sig.decl.output + { + // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric` + self.ty_bounds.push(ExplicitTyBound(true)); + for stmt in *stmts { + self.visit_stmt(stmt); + } + self.ty_bounds.pop(); + // Ignore return expr since we know its type was inferred from return ty + return; + } + }, + + // Ignore return expr since we know its type was inferred from return ty + ExprKind::Ret(_) => return, + ExprKind::Call(func, args) => { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) { - // Push found arg type, then visit arg. - self.ty_bounds.push((*bound).into()); - self.visit_expr(expr); - self.ty_bounds.pop(); + // If is from macro, try to use last bound type (typically pushed when visiting stmt), + // otherwise push found arg type, then visit arg, + if expr.span.from_expansion() { + self.visit_expr(expr); + } else { + self.ty_bounds.push((*bound).into()); + self.visit_expr(expr); + self.ty_bounds.pop(); + } } return; } @@ -137,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); - for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { + for (expr, bound) in iter::zip(iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { self.ty_bounds.push((*bound).into()); self.visit_expr(expr); self.ty_bounds.pop(); diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs similarity index 62% rename from clippy_lints/src/empty_structs_with_brackets.rs rename to clippy_lints/src/empty_with_brackets.rs index 3cf67b3ecbfa..969df6d85b5a 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Item, ItemKind, VariantData}; +use rustc_ast::ast::{Item, ItemKind, Variant, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -27,9 +27,38 @@ declare_clippy_lint! { restriction, "finds struct declarations with empty brackets" } -declare_lint_pass!(EmptyStructsWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS]); -impl EarlyLintPass for EmptyStructsWithBrackets { +declare_clippy_lint! { + /// ### What it does + /// Finds enum variants without fields that are declared with empty brackets. + /// + /// ### Why is this bad? + /// Empty brackets while defining enum variants are redundant and can be omitted. + /// + /// ### Example + /// ```no_run + /// enum MyEnum { + /// HasData(u8), + /// HasNoData(), // redundant parentheses + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// enum MyEnum { + /// HasData(u8), + /// HasNoData, + /// } + /// ``` + #[clippy::version = "1.77.0"] + pub EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + restriction, + "finds enum variants with empty brackets" +} + +declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]); + +impl EarlyLintPass for EmptyWithBrackets { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { let span_after_ident = item.span.with_lo(item.ident.span.hi()); @@ -53,6 +82,27 @@ impl EarlyLintPass for EmptyStructsWithBrackets { ); } } + + fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) { + let span_after_ident = variant.span.with_lo(variant.ident.span.hi()); + + if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) { + span_lint_and_then( + cx, + EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + span_after_ident, + "enum variant has empty brackets", + |diagnostic| { + diagnostic.span_suggestion_hidden( + span_after_ident, + "remove the brackets", + "", + Applicability::MaybeIncorrect, + ); + }, + ); + } + } } fn has_no_ident_token(braces_span_str: &str) -> bool { diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index cd6c46a71a8e..8f48941c4a91 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; -use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use clippy_utils::{contains_return, higher, in_constant, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; @@ -74,6 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + // `bool::then()` and `bool::then_some()` are not const + if in_constant(cx, expr.hir_id) { + return; + } + let ctxt = expr.span.ctxt(); if let Some(higher::If { diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 655f4b82aa4f..17b6256f982b 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Lints subtraction between an [`Instant`] and a [`Duration`]. + /// Lints subtraction between an `Instant` and a `Duration`. /// /// ### Why is this bad? /// Unchecked subtraction could cause underflow on certain platforms, leading to @@ -57,9 +57,6 @@ declare_clippy_lint! { /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` - /// - /// [`Duration`]: std::time::Duration - /// [`Instant::now()`]: std::time::Instant::now; #[clippy::version = "1.67.0"] pub UNCHECKED_DURATION_SUBTRACTION, pedantic, diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index a9f1612ff05e..276c1abb60cd 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -1,6 +1,7 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; +use clippy_utils::is_bool; use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; @@ -231,6 +232,10 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: & (false, _) => ("pre", prefix), (true, false) => ("post", postfix), }; + if fields.iter().all(|field| is_bool(field.ty)) { + // If all fields are booleans, we don't want to emit this lint. + return; + } span_lint_and_help( cx, STRUCT_FIELD_NAMES, diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index c9dc48668f29..903d3a2ab896 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -5,7 +5,8 @@ use clippy_utils::ty::{implements_trait, make_normalized_projection}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; @@ -152,7 +153,8 @@ fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { - if let ItemKind::Impl(imp) = item.kind + if !in_external_macro(cx.sess(), item.span) + && let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait && trait_ref @@ -219,7 +221,8 @@ impl {self_ty_without_ref} {{ _ => return, }; - if let ImplItemKind::Fn(sig, _) = item.kind + if !in_external_macro(cx.sess(), item.span) + && let ImplItemKind::Fn(sig, _) = item.kind && let FnRetTy::Return(ret) = sig.decl.output && is_nameable_in_impl_trait(ret) && cx.tcx.generics_of(item_did).params.is_empty() diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 755a4ff525d2..efdd39259497 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -115,7 +115,7 @@ mod duplicate_mod; mod else_if_without_else; mod empty_drop; mod empty_enum; -mod empty_structs_with_brackets; +mod empty_with_brackets; mod endian_bytes; mod entry; mod enum_clike; @@ -272,6 +272,7 @@ mod permissions_set_readonly_false; mod precedence; mod ptr; mod ptr_offset_with_cast; +mod pub_underscore_fields; mod pub_use; mod question_mark; mod question_mark_used; @@ -322,6 +323,7 @@ mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; mod tests_outside_test_module; +mod thread_local_initializer_can_be_made_const; mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; @@ -571,6 +573,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { verbose_bit_mask_threshold, warn_on_all_wildcard_imports, check_private_items, + pub_underscore_fields_behavior, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -947,7 +950,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); - store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets)); + store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets)); store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); @@ -1080,7 +1083,15 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity)); store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences)); store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)); - store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion)); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(move |_| { + Box::new(pub_underscore_fields::PubUnderscoreFields { + behavior: pub_underscore_fields_behavior, + }) + }); + store.register_late_pass(move |_| { + Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv())) + }); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 8a0955147bb5..29957e423b0b 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -96,8 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) .opt_def_id() - .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) - .unwrap_or_default(), + .is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)), // Detect `|x| x.ok()` ExprKind::Closure(Closure { body, .. }) => { if let Body { diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 7cfd3d346b63..e489899c19e3 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -26,13 +26,14 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if ident.name == method_name && let hir::ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) + && !body.params.is_empty() { + let arg_id = body.params[0].pat.hir_id; return arg_id == *local; } false diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index ade8e3155fae..9f84321ced4a 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -1,80 +1,181 @@ +use clippy_utils::ty::get_iterator_item_ty; +use hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; -fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { - match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, - hir::ExprKind::Path(QPath::Resolved(_, segments)) => { - segments.segments.last().unwrap().ident.name == method_name +/// +/// Returns true if the expression is a method call to `method_name` +/// e.g. `a.method_name()` or `Option::method_name`. +/// +/// The type-checker verifies for us that the method accepts the right kind of items +/// (e.g. `Option::is_some` accepts `Option<_>`), so we don't need to check that. +/// +/// How to capture each case: +/// +/// `.filter(|a| { std::option::Option::is_some(a) })` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a closure, getting unwrapped and +/// recursively checked. +/// `std::option::Option::is_some(a)` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a call. It unwraps to a path with +/// `QPath::TypeRelative`. Since this is a type relative path, we need to check the method name, the +/// type, and that the parameter of the closure is passed in the call. This part is the dual of +/// `receiver.method_name()` below. +/// +/// `filter(std::option::Option::is_some);` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a type relative path, like above, we check the +/// type and the method name. +/// +/// `filter(|a| a.is_some());` +/// ^^^^^^^^^^^^^^^ <- this is a method call inside a closure, +/// we check that the parameter of the closure is the receiver of the method call and don't allow +/// any other parameters. +fn is_method( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + type_symbol: Symbol, + method_name: Symbol, + params: &[&hir::Pat<'_>], +) -> bool { + fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool { + match param.kind { + hir::PatKind::Binding(_, _, other, _) => ident == other, + hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat), + _ => false, + } + } + match expr.kind { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { + // compare the identifier of the receiver to the parameter + // we are in a filter => closure has a single parameter and a single, non-block + // expression, this means that the parameter shadows all outside variables with + // the same name => avoid FPs. If the parameter is not the receiver, then this hits + // outside variables => avoid FP + if ident.name == method_name + && let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + // This is used to check for complete paths via `|a| std::option::Option::is_some(a)` + // this then unwraps to a path with `QPath::TypeRelative` + // we pass the params as they've been passed to the current call through the closure + hir::ExprKind::Call(expr, [param]) => { + // this will hit the `QPath::TypeRelative` case and check that the method name is correct + if is_method(cx, expr, type_symbol, method_name, params) + // we then check that this is indeed passing the parameter of the closure + && let ExprKind::Path(QPath::Resolved(None, path)) = param.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => { + let ty = cx.typeck_results().node_type(ty.hir_id); + if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol) + && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def() + { + return mname.ident.name == method_name; + } + false }, - hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; - match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { - if ident.name == method_name - && let hir::ExprKind::Path(path) = &receiver.kind - && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) - { - return arg_id == *local; - } - false - }, - _ => false, - } + let params = body.params.iter().map(|param| param.pat).collect::>(); + is_method(cx, closure_expr, type_symbol, method_name, params.as_slice()) }, _ => false, } } fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) { - is_method(cx, parent_expr, rustc_span::sym::map) - } else { - false + if let Some(expr) = get_parent_expr(cx, expr) + && is_trait_method(cx, expr, sym::Iterator) + && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind + && path.ident.name == rustc_span::sym::map + { + return true; } + false } -#[allow(clippy::too_many_arguments)] -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) { - let is_iterator = is_trait_method(cx, expr, sym::Iterator); - let parent_is_not_map = !parent_is_map(cx, expr); +enum FilterType { + IsSome, + IsOk, +} - if is_iterator - && parent_is_not_map - && is_method(cx, filter_arg, sym!(is_some)) - && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) +/// Returns the `FilterType` of the expression if it is a filter over an Iter