From e7fbf7223f640c5121b21183cd26ecd3ccb6a820 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 20 Mar 2024 01:27:33 -0700 Subject: [PATCH 0001/1110] improve codegen of fmt_num to delete unreachable panic it seems LLVM doesn't realize that `curr` is always decremented at least once in either loop formatting characters of the input string by their appropriate radix, and so the later `&buf[curr..]` generates a check for out-of-bounds access and panic. this is unreachable in reality as even for `x == T::zero()` we'll produce at least the character `Self::digit(T::zero())` for at least one character output, and `curr` will always be at least one below `buf.len()`. adjust `fmt_int` to make this fact more obvious to the compiler, which fortunately (or unfortunately) results in a measurable performance improvement for workloads heavy on formatting integers. --- library/core/src/fmt/num.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index ab2158394bf1e..abe833a4bf2d7 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -79,11 +79,11 @@ unsafe trait GenericRadix: Sized { if is_nonnegative { // Accumulate each digit of the number from the least significant // to the most significant figure. - for byte in buf.iter_mut().rev() { + loop { let n = x % base; // Get the current place value. x = x / base; // Deaccumulate the number. - byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; + buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; @@ -91,11 +91,11 @@ unsafe trait GenericRadix: Sized { } } else { // Do the same as above, but accounting for two's complement. - for byte in buf.iter_mut().rev() { + loop { let n = zero - (x % base); // Get the current place value. x = x / base; // Deaccumulate the number. - byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; + buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; From cea973f857b63e7c208e822d95c06c4883062449 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 23 Mar 2024 11:33:09 -0700 Subject: [PATCH 0002/1110] try adding a test that LowerHex and friends don't panic, but it doesn't work --- library/core/benches/fmt.rs | 14 ++++++++++++++ tests/codegen/fmt_int_no_panic.rs | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/codegen/fmt_int_no_panic.rs diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs index d1cdb12e50f8c..a02bd60654251 100644 --- a/library/core/benches/fmt.rs +++ b/library/core/benches/fmt.rs @@ -148,3 +148,17 @@ fn write_u64_min(bh: &mut Bencher) { test::black_box(format!("{}", 0u64)); }); } + +#[bench] +fn write_u8_max(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", u8::MAX)); + }); +} + +#[bench] +fn write_u8_min(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", 0u8)); + }); +} diff --git a/tests/codegen/fmt_int_no_panic.rs b/tests/codegen/fmt_int_no_panic.rs new file mode 100644 index 0000000000000..efd0530bc8884 --- /dev/null +++ b/tests/codegen/fmt_int_no_panic.rs @@ -0,0 +1,24 @@ +// Trying to check that formatting u8/u32/u64/etc do not panic. +// +// This test does not correctly do so yet. + +//@ compile-flags: -O + +#![crate_type = "lib"] + +// expected to need to write some kind of `impl core::fmt::Write` on a struct like this to avoid +// unrelated panics if `String::write_str` can't make space.. +// struct CanAlwaysBeWrittenTo; + +use std::fmt::Write; + +// CHECK-LABEL: @format_int_doesnt_panic +#[no_mangle] +pub fn format_int_doesnt_panic(s: &mut String) -> std::fmt::Result { + // CHECK-NOT: panic + // ... but wait! this will definitely panic if `s.vec.reserve_for_push()` cannot alloc! this + // shouldn't pass! + write!(s, "{:x}", 0u8)?; + write!(s, "{:x}", u8::MAX)?; + Ok(()) +} From 4a5bcbb4e4fb402719d0d6c4da17a3ca43be66c2 Mon Sep 17 00:00:00 2001 From: chloekek Date: Mon, 15 Apr 2024 00:23:05 +0200 Subject: [PATCH 0003/1110] Add vec_deque::Iter::as_slices and friends Add the following methods, that work similarly to VecDeque::as_slices: - alloc::collections::vec_deque::Iter::as_slices - alloc::collections::vec_deque::IterMut::into_slices - alloc::collections::vec_deque::IterMut::as_slices - alloc::collections::vec_deque::IterMut::as_mut_slices Obtaining slices from a VecDeque iterator was not previously possible. --- .../alloc/src/collections/vec_deque/iter.rs | 34 ++++++ .../src/collections/vec_deque/iter_mut.rs | 107 ++++++++++++++++++ library/alloc/src/lib.rs | 1 + 3 files changed, 142 insertions(+) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 5a5e7f70854d8..74eeed3f9e1a8 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> { pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// This has the same lifetime as the original `VecDeque`, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&'a [T], &'a [T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 5061931afb7b7..db81f0d1e1d95 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> { pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to + /// consume the iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// let slices = iter.into_slices(); + /// slices.0[0] = 42; + /// slices.1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) { + (self.i1.into_slice(), self.i2.into_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&[T], &[T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// iter.as_mut_slices().0[0] = 42; + /// iter.as_mut_slices().1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + (self.i1.as_mut_slice(), self.i2.as_mut_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dec04d7e421e3..9862af7f1e7a8 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -150,6 +150,7 @@ #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] +#![feature(slice_iter_mut_as_mut_slice)] #![feature(slice_ptr_get)] #![feature(slice_range)] #![feature(std_internals)] From 040929bc11041fb3ba34a5399edb16e2993f17e1 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 3 Jun 2024 21:49:09 -0400 Subject: [PATCH 0004/1110] Revert "Rollup merge of #125472 - erikdesjardins:component, r=clubby789" This reverts commit 64730a1632f4b13923ee32782cd4718613aea9a3, reversing changes made to 80aea305d388bd39a1bb5d92212de8fbde100c97. --- src/tools/tidy/src/target_specific_tests.rs | 34 --------------------- 1 file changed, 34 deletions(-) diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index f3a64b38e8c66..c876aae494dd5 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -10,26 +10,6 @@ use crate::walk::filter_not_rust; const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:"; const COMPILE_FLAGS_HEADER: &str = "compile-flags:"; -const KNOWN_LLVM_COMPONENTS: &[&str] = &[ - "aarch64", - "arm", - "avr", - "bpf", - "csky", - "hexagon", - "loongarch", - "m68k", - "mips", - "msp430", - "nvptx", - "powerpc", - "riscv", - "sparc", - "systemz", - "webassembly", - "x86", -]; - #[derive(Default, Debug)] struct RevisionInfo<'a> { target_arch: Option<&'a str>, @@ -88,20 +68,6 @@ pub fn check(path: &Path, bad: &mut bool) { // gathered. } } - if let Some(llvm_components) = llvm_components { - for component in llvm_components { - // Ensure the given component even exists. - // This is somewhat redundant with COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS, - // but helps detect such problems earlier (PR CI rather than bors CI). - if !KNOWN_LLVM_COMPONENTS.contains(component) { - eprintln!( - "{}: revision {} specifies unknown LLVM component `{}`", - file, rev, component - ); - *bad = true; - } - } - } } }); } From 6a5a88eb6e7a3494902f95b07d074621fb69cd8b Mon Sep 17 00:00:00 2001 From: ilikdoge Date: Wed, 24 Jul 2024 19:07:14 -0700 Subject: [PATCH 0005/1110] Implement `mixed_integer_ops_unsigned_sub` --- library/core/src/num/uint_macros.rs | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e6bdc4d450d4a..7d39040a6a20d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -765,6 +765,33 @@ macro_rules! uint_impl { } } + /// Checked subtraction with a signed integer. Computes `self - rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(2), None);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(-2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_sub_signed(-4), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_signed(self, rhs: $SignedT) -> Option { + let (res, overflow) = self.overflowing_sub_signed(rhs); + + if !overflow { + Some(res) + } else { + None + } + } + #[doc = concat!( "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", stringify!($SignedT), "`], returning `None` if overflow occurred." @@ -1757,6 +1784,35 @@ macro_rules! uint_impl { intrinsics::saturating_sub(self, rhs) } + /// Saturating integer subtraction. Computes `self` - `rhs`, saturating at + /// the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(2), 0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(-2), 3);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_sub_signed(-4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_signed(self, rhs: $SignedT) -> Self { + let (res, overflow) = self.overflowing_sub_signed(rhs); + + if !overflow { + res + } else if rhs < 0 { + Self::MAX + } else { + 0 + } + } + /// Saturating integer multiplication. Computes `self * rhs`, /// saturating at the numeric bounds instead of overflowing. /// @@ -1890,6 +1946,27 @@ macro_rules! uint_impl { intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) subtraction with a signed integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(-2), 3);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_sub_signed(-4), 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub_signed(self, rhs: $SignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * /// rhs`, wrapping around at the boundary of the type. /// @@ -2328,6 +2405,32 @@ macro_rules! uint_impl { (c, b || d) } + /// Calculates `self` - `rhs` with a signed `rhs` + /// + /// Returns a tuple of the subtraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(-2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_sub_signed(-4), (1, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_signed(self, rhs: $SignedT) -> (Self, bool) { + let (res, overflow) = self.overflowing_sub(rhs as Self); + + (res, overflow ^ (rhs < 0)) + } + /// Computes the absolute difference between `self` and `other`. /// /// # Examples From ad3f3c7fb67329778bf26771cd4fbfc68e175daf Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 25 Jul 2024 17:53:29 +0000 Subject: [PATCH 0006/1110] Skip locking span interner for some syntax context checks --- compiler/rustc_span/src/lib.rs | 6 ------ compiler/rustc_span/src/span_encoding.rs | 14 +++++++++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7c8ac3be4beca..6cb8491067d2c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -564,12 +564,6 @@ impl Span { !self.is_dummy() && sm.is_span_accessible(self) } - /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. - #[inline] - pub fn from_expansion(self) -> bool { - !self.ctxt().is_root() - } - /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 53d7b7511a621..f56da203fa8c3 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -305,6 +305,13 @@ impl Span { } } + /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. + #[inline] + pub fn from_expansion(self) -> bool { + // If the span is fully inferred then ctxt > MAX_CTXT + self.inline_ctxt().map_or(true, |ctxt| !ctxt.is_root()) + } + /// Returns `true` if this is a dummy span with any hygienic context. #[inline] pub fn is_dummy(self) -> bool { @@ -372,9 +379,10 @@ impl Span { pub fn eq_ctxt(self, other: Span) -> bool { match (self.inline_ctxt(), other.inline_ctxt()) { (Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2, - (Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => { - with_span_interner(|interner| ctxt == interner.spans[index].ctxt) - } + // If `inline_ctxt` returns `Ok` the context is <= MAX_CTXT. + // If it returns `Err` the span is fully interned and the context is > MAX_CTXT. + // As these do not overlap an `Ok` and `Err` result cannot have an equal context. + (Ok(_), Err(_)) | (Err(_), Ok(_)) => false, (Err(index1), Err(index2)) => with_span_interner(|interner| { interner.spans[index1].ctxt == interner.spans[index2].ctxt }), From 858d6d136a7943d79cacc0c24816e80d2a6ad67a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 13 Aug 2024 23:50:33 +0200 Subject: [PATCH 0007/1110] Make `std::os::darwin` public This includes `std::os::darwin::fs`, which is re-exported under `std::os::macos::fs` and `std::os::ios::fs`. `std::os::darwin::raw` is not exposed, which means that `MetadataExt::as_raw_stat` isn't available on tvOS, visionOS and watchOS. --- library/std/src/os/darwin/fs.rs | 17 +++++++++++------ library/std/src/os/darwin/mod.rs | 5 ++++- library/std/src/os/ios/mod.rs | 2 -- library/std/src/os/macos/mod.rs | 2 -- library/std/src/os/mod.rs | 24 +++++++++++++++++++++--- library/std/src/os/unix/mod.rs | 2 +- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/library/std/src/os/darwin/fs.rs b/library/std/src/os/darwin/fs.rs index 2d154b214b5f0..5740c86e62183 100644 --- a/library/std/src/os/darwin/fs.rs +++ b/library/std/src/os/darwin/fs.rs @@ -1,7 +1,8 @@ -#![allow(dead_code)] +//! Darwin-specific extension traits to [`fs`]. +//! +//! [`fs`]: crate::fs +#![stable(feature = "metadata_ext", since = "1.1.0")] -#[allow(deprecated)] -use super::raw; use crate::fs::{self, Metadata}; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; @@ -25,7 +26,10 @@ pub trait MetadataExt { methods of this trait" )] #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; + // Only available on macOS and iOS, since they were stably exposed there. + #[cfg(any(doc, target_os = "macos", target_os = "ios"))] + #[doc(cfg(any(target_os = "macos", target_os = "ios")))] + fn as_raw_stat(&self) -> &super::raw::stat; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; @@ -77,8 +81,9 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + #[cfg(any(doc, target_os = "macos", target_os = "ios"))] + fn as_raw_stat(&self) -> &super::raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs index 03401fe8895b9..7a057ddb861b7 100644 --- a/library/std/src/os/darwin/mod.rs +++ b/library/std/src/os/darwin/mod.rs @@ -13,7 +13,10 @@ //! `aarch64-apple-darwin` target names, which are mostly named that way for //! legacy reasons. -pub(crate) mod fs; +#![stable(feature = "os_darwin", since = "CURRENT_RUSTC_VERSION")] +#![doc(cfg(target_vendor = "apple"))] + +pub mod fs; // deprecated, but used for public reexport under `std::os::unix::raw`, as // well as `std::os::macos`/`std::os::ios`, because those modules precede the // decision to remove these. diff --git a/library/std/src/os/ios/mod.rs b/library/std/src/os/ios/mod.rs index 52d592ed95afa..bd18fc2fa0ca9 100644 --- a/library/std/src/os/ios/mod.rs +++ b/library/std/src/os/ios/mod.rs @@ -4,10 +4,8 @@ #[stable(feature = "metadata_ext", since = "1.1.0")] pub mod fs { - #[doc(inline)] #[stable(feature = "file_set_times", since = "1.75.0")] pub use crate::os::darwin::fs::FileTimesExt; - #[doc(inline)] #[stable(feature = "metadata_ext", since = "1.1.0")] pub use crate::os::darwin::fs::MetadataExt; } diff --git a/library/std/src/os/macos/mod.rs b/library/std/src/os/macos/mod.rs index 59fe90834c2b4..0681c9b714816 100644 --- a/library/std/src/os/macos/mod.rs +++ b/library/std/src/os/macos/mod.rs @@ -4,10 +4,8 @@ #[stable(feature = "metadata_ext", since = "1.1.0")] pub mod fs { - #[doc(inline)] #[stable(feature = "file_set_times", since = "1.75.0")] pub use crate::os::darwin::fs::FileTimesExt; - #[doc(inline)] #[stable(feature = "metadata_ext", since = "1.1.0")] pub use crate::os::darwin::fs::MetadataExt; } diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 020a8b324f410..19b7d4d42e3e2 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -15,7 +15,16 @@ pub mod raw; // documented don't compile (missing things in `libc` which is empty), // so just omit them with an empty module and add the "unstable" attribute. -// unix, linux, wasi and windows are handled a bit differently. +// darwin, unix, linux, wasi and windows are handled a bit differently. +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod darwin {} #[cfg(all( doc, any( @@ -53,6 +62,17 @@ pub mod wasi {} #[unstable(issue = "none", feature = "std_internals")] pub mod windows {} +// darwin +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_vendor = "apple", doc))] +pub mod darwin; + // unix #[cfg(not(all( doc, @@ -105,8 +125,6 @@ pub mod windows; pub mod aix; #[cfg(target_os = "android")] pub mod android; -#[cfg(target_vendor = "apple")] -pub(crate) mod darwin; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "emscripten")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index c6581b9c4c8c8..ace9fb445f572 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -42,7 +42,7 @@ mod platform { #[cfg(target_os = "android")] pub use crate::os::android::*; #[cfg(target_vendor = "apple")] - pub(super) use crate::os::darwin::*; + pub use crate::os::darwin::*; #[cfg(target_os = "dragonfly")] pub use crate::os::dragonfly::*; #[cfg(target_os = "emscripten")] From a9ecd0fa8141e7614ca35d5a4d2fe5c96b1a7890 Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Thu, 22 Aug 2024 14:29:57 +0200 Subject: [PATCH 0008/1110] Expand std::os::unix::fs::chown() doc with a warning Include warning about losing setuid/gid when chowning, per POSIX. --- library/std/src/os/unix/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index caf6980afd91b..f063fa06cc959 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -985,6 +985,10 @@ impl DirBuilderExt for fs::DirBuilder { /// Changing the owner typically requires privileges, such as root or a specific capability. /// Changing the group typically requires either being the owner and a member of the group, or /// having privileges. +/// +/// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases +/// according to POSIX, usually even if the user is root. The sgid is not cleared when +/// the file is non-group-executable. /// /// If called on a symbolic link, this will change the owner and group of the link target. To /// change the owner and group of the link itself, see [`lchown`]. From 3408dc1eb5f8d744b4d7d5a4392ae6456f036ad9 Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Thu, 22 Aug 2024 18:38:27 +0200 Subject: [PATCH 0009/1110] Update chown help with a link and adding cap warning Linked to chown(2) manpage on the web which expands on chown call behaviour. --- library/std/src/os/unix/fs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index f063fa06cc959..92613d9b004ce 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -988,7 +988,8 @@ impl DirBuilderExt for fs::DirBuilder { /// /// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases /// according to POSIX, usually even if the user is root. The sgid is not cleared when -/// the file is non-group-executable. +/// the file is non-group-executable. See: +/// This call may also clear file capabilities, if there was any. /// /// If called on a symbolic link, this will change the owner and group of the link target. To /// change the owner and group of the link itself, see [`lchown`]. From 32b608a439ef0015251b7339b4ab33d72be2397e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:20:46 +0000 Subject: [PATCH 0010/1110] Merge commit '6d35b4c9a04580366fd800692a5b5db79d766530' into sync_cg_clif-2024-09-22 --- .cirrus.yml | 2 +- .github/workflows/main.yml | 3 +- Cargo.lock | 64 +++++----- Cargo.toml | 14 +-- build_system/abi_cafe.rs | 9 +- build_system/bench.rs | 37 +++++- build_system/build_backend.rs | 17 +-- build_system/build_sysroot.rs | 85 ++++++-------- build_system/main.rs | 7 -- build_system/path.rs | 5 +- build_system/prepare.rs | 98 +++++----------- build_system/tests.rs | 43 ++----- build_system/usage.txt | 16 +-- build_system/utils.rs | 110 ++++++------------ clean_all.sh | 5 +- example/neon.rs | 43 +++++++ example/std_example.rs | 28 +++++ ...-simd-Disable-broken-reduce_sum-test.patch | 26 +++++ ...oretests-Disable-not-compiling-tests.patch | 2 +- ...7-coretests-128bit-atomic-operations.patch | 5 +- ...coretests-Disable-long-running-tests.patch | 20 ++++ rust-toolchain | 2 +- scripts/setup_rust_fork.sh | 3 + scripts/test_rustc_tests.sh | 92 +++++++++++++++ src/abi/mod.rs | 5 +- src/constant.rs | 5 + src/intrinsics/llvm_aarch64.rs | 38 ++++++ src/intrinsics/mod.rs | 4 +- src/intrinsics/simd.rs | 42 +++---- test.sh | 2 +- y.sh | 2 +- 31 files changed, 487 insertions(+), 347 deletions(-) create mode 100644 patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch diff --git a/.cirrus.yml b/.cirrus.yml index 5a464bfac3644..1ec99eb3d17a5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -3,7 +3,7 @@ task: freebsd_instance: image: freebsd-13-2-release-amd64 setup_rust_script: - - pkg install -y git bash binutils + - pkg install -y git-tiny binutils - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh --default-toolchain none -y --profile=minimal target_cache: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 896a5c34c3eff..2ee94146c1a4e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -279,8 +279,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/master' }} - # FIXME add the bench job back to the dependency list once rust-lang/rust#125493 gets merged - needs: [rustfmt, test, dist] + needs: [rustfmt, test, bench, dist] permissions: contents: write # for creating the dev tag and release diff --git a/Cargo.lock b/Cargo.lock index 02d4d98dc4212..1c2ca95b075ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effa84ab2023f7138045ece6b326588c17447ca22e66db71ec15cb0a6c0c4ad2" +checksum = "b80c3a50b9c4c7e5b5f73c0ed746687774fc9e36ef652b110da8daebf0c6e0e6" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a1dfc50dca188a15d938867c4400589530bcb0138f7022aae6d059d1d8c309" +checksum = "38778758c2ca918b05acb2199134e0c561fb577c50574259b26190b6c2d95ded" [[package]] name = "cranelift-codegen" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821c20c639350158ecca928dc2a244d0d1c9cef2377a378fc62a445a286eb1ca" +checksum = "58258667ad10e468bfc13a8d620f50dfcd4bb35d668123e97defa2549b9ad397" dependencies = [ "bumpalo", "cranelift-bforest", @@ -84,42 +84,42 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064473f2fd59b44fa2c9aaa60de1f9c44db5e13521e28bc85d2b92ee535ef625" +checksum = "043f0b702e529dcb07ff92bd7d40e7d5317b5493595172c5eb0983343751ee06" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f39b9ebfd2febdc2acfb9a0fca110665bcd5a6839502576307735ed07b2177" +checksum = "7763578888ab53eca5ce7da141953f828e82c2bfadcffc106d10d1866094ffbb" [[package]] name = "cranelift-control" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e125c189c3a1ca8dfe209fc6f46edba058a6d24e0b92aff69459a15f4711e7" +checksum = "32db15f08c05df570f11e8ab33cb1ec449a64b37c8a3498377b77650bef33d8b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea62eb109baec2247e1a6fa7b74c0f584b1e76e289cfd7017385b4b031fc8450" +checksum = "5289cdb399381a27e7bbfa1b42185916007c3d49aeef70b1d01cb4caa8010130" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722b089357aacb6c7528b2e59a5fe00917d61ce63448b25a3e477a5b7819fac8" +checksum = "31ba8ab24eb9470477e98ddfa3c799a649ac5a0d9a2042868c4c952133c234e8" dependencies = [ "cranelift-codegen", "log", @@ -129,15 +129,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b5005a48288e7fc2a2991a377831c534e26929b063c379c018060727785a9b" +checksum = "2b72a3c5c166a70426dcb209bdd0bb71a787c1ea76023dc0974fbabca770e8f9" [[package]] name = "cranelift-jit" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f843932baf8d1025c5f114b929eda172d74b7163d058e0de2597c308b567c7e9" +checksum = "df32578a47582e49b4fc1f9a5786839d9be1fedaa9f00bea7612c54425663c6b" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449819ef1c4af139cf1b9717916fcaea0e23248853d3e95135139773a842d3eb" +checksum = "96094a758cdb543c9143f70817cd31069fecd49f50981a0fac06820ac011dc2f" dependencies = [ "anyhow", "cranelift-codegen", @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2d48f38081a9e679ad795bd36bb29bedeb5552fc1c195185bf9885fa1b16e" +checksum = "46a42424c956bbc31fc5c2706073df896156c5420ae8fa2a5d48dbc7b295d71b" dependencies = [ "cranelift-codegen", "libc", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.110.1" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a39ee2cfd0ec485eca76f6b4dc17701a280fa406bc05137bb43f1635ed12c9f" +checksum = "1cf5e2484ab47fe38a3150747cdd2016535f13542a925acca152b63383a6591b" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +213,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" dependencies = [ "fallible-iterator", "indexmap", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.15" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "unicode-ident" @@ -421,9 +421,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "23.0.1" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fddf3e2980fb1d123d1fcac55189e417fdd3dba4f62139b5a0a1f9efe5669d5" +checksum = "d15de8429db996f0d17a4163a35eccc3f874cbfb50f29c379951ea1bbb39452e" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index a0df502dadc47..6594ffb5d66bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,14 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.110.1", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.110.1" } -cranelift-module = { version = "0.110.1" } -cranelift-native = { version = "0.110.1" } -cranelift-jit = { version = "0.110.1", optional = true } -cranelift-object = { version = "0.110.1" } +cranelift-codegen = { version = "0.111.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.111.0" } +cranelift-module = { version = "0.111.0" } +cranelift-native = { version = "0.111.0" } +cranelift-jit = { version = "0.111.0", optional = true } +cranelift-object = { version = "0.111.0" } target-lexicon = "0.12.0" -gimli = { version = "0.28", default-features = false, features = ["write"]} +gimli = { version = "0.29", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index c0873a20e535a..9292778806a2e 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -14,7 +14,6 @@ static ABI_CAFE_REPO: GitRepo = GitRepo::github( static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); pub(crate) fn run( - channel: &str, sysroot_kind: SysrootKind, dirs: &Dirs, cg_clif_dylib: &CodegenBackend, @@ -28,7 +27,6 @@ pub(crate) fn run( eprintln!("Building sysroot for abi-cafe"); build_sysroot::build_sysroot( dirs, - channel, sysroot_kind, cg_clif_dylib, bootstrap_host_compiler, @@ -38,12 +36,11 @@ pub(crate) fn run( eprintln!("Running abi-cafe"); - let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; - let pairs = + let pairs: &[_] = if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) { - &pairs[..] + &["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"] } else { - &pairs[..2] + &["rustc_calls_cgclif", "cgclif_calls_rustc"] }; let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); diff --git a/build_system/bench.rs b/build_system/bench.rs index 501e128d18039..ebeb67722507a 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -1,11 +1,12 @@ use std::env; use std::io::Write; use std::path::Path; +use std::process::Command; use crate::path::{Dirs, RelPath}; use crate::prepare::GitRepo; use crate::rustc_info::get_file_name; -use crate::utils::{Compiler, hyperfine_command, spawn_and_wait}; +use crate::utils::{Compiler, spawn_and_wait}; static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( "ebobby", @@ -128,3 +129,37 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { gha_step_summary.write_all(b"\n").unwrap(); } } + +#[must_use] +fn hyperfine_command( + warmup: u64, + runs: u64, + prepare: Option<&str>, + cmds: &[(&str, &str)], + markdown_export: &Path, +) -> Command { + let mut bench = Command::new("hyperfine"); + + bench.arg("--export-markdown").arg(markdown_export); + + if warmup != 0 { + bench.arg("--warmup").arg(warmup.to_string()); + } + + if runs != 0 { + bench.arg("--runs").arg(runs.to_string()); + } + + if let Some(prepare) = prepare { + bench.arg("--prepare").arg(prepare); + } + + for &(name, cmd) in cmds { + if name != "" { + bench.arg("-n").arg(name); + } + bench.arg(cmd); + } + + bench +} diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index 129713e574ad0..02da89f737cf2 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -6,11 +6,10 @@ use crate::rustc_info::get_file_name; use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; use crate::utils::{CargoProject, Compiler, LogGroup}; -pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); +static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, - channel: &str, bootstrap_host_compiler: &Compiler, use_unstable_features: bool, ) -> PathBuf { @@ -19,8 +18,8 @@ pub(crate) fn build_backend( let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); let mut rustflags = rustflags_from_env("RUSTFLAGS"); - rustflags.push("-Zallow-features=rustc_private".to_owned()); + rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { // Enabling debug assertions implicitly enables the clif ir verifier @@ -32,15 +31,7 @@ pub(crate) fn build_backend( cmd.arg("--features").arg("unstable-features"); } - match channel { - "debug" => {} - "release" => { - cmd.arg("--release"); - } - _ => unreachable!(), - } - - rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); + cmd.arg("--release"); eprintln!("[BUILD] rustc_codegen_cranelift"); crate::utils::spawn_and_wait(cmd); @@ -48,6 +39,6 @@ pub(crate) fn build_backend( CG_CLIF .target_dir(dirs) .join(&bootstrap_host_compiler.triple) - .join(channel) + .join("release") .join(get_file_name(&bootstrap_host_compiler.rustc, "rustc_codegen_cranelift", "dylib")) } diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index b11dc6a0eed8f..6a4f2a6c72c52 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -3,19 +3,15 @@ use std::process::Command; use std::{env, fs}; use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_file_name; +use crate::prepare::apply_patches; +use crate::rustc_info::{get_default_sysroot, get_file_name}; use crate::utils::{ - CargoProject, Compiler, LogGroup, remove_dir_if_exists, spawn_and_wait, try_hard_link, + ensure_empty_dir, spawn_and_wait, try_hard_link, CargoProject, Compiler, LogGroup, }; -use crate::{CodegenBackend, SysrootKind, config}; - -static DIST_DIR: RelPath = RelPath::DIST; -static BIN_DIR: RelPath = RelPath::DIST.join("bin"); -static LIB_DIR: RelPath = RelPath::DIST.join("lib"); +use crate::{config, CodegenBackend, SysrootKind}; pub(crate) fn build_sysroot( dirs: &Dirs, - channel: &str, sysroot_kind: SysrootKind, cg_clif_dylib_src: &CodegenBackend, bootstrap_host_compiler: &Compiler, @@ -26,9 +22,11 @@ pub(crate) fn build_sysroot( eprintln!("[BUILD] sysroot {:?}", sysroot_kind); - DIST_DIR.ensure_fresh(dirs); - BIN_DIR.ensure_exists(dirs); - LIB_DIR.ensure_exists(dirs); + let dist_dir = RelPath::DIST.to_path(dirs); + + ensure_empty_dir(&dist_dir); + fs::create_dir_all(dist_dir.join("bin")).unwrap(); + fs::create_dir_all(dist_dir.join("lib")).unwrap(); let is_native = bootstrap_host_compiler.triple == target_triple; @@ -38,11 +36,10 @@ pub(crate) fn build_sysroot( let cg_clif_dylib_path = if cfg!(windows) { // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the // binaries. - BIN_DIR + dist_dir.join("bin") } else { - LIB_DIR + dist_dir.join("lib") } - .to_path(dirs) .join(src_path.file_name().unwrap()); try_hard_link(src_path, &cg_clif_dylib_path); CodegenBackend::Local(cg_clif_dylib_path) @@ -56,7 +53,7 @@ pub(crate) fn build_sysroot( let wrapper_name = wrapper_base_name.replace("____", wrapper); let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc); - let wrapper_path = DIST_DIR.to_path(dirs).join(&wrapper_name); + let wrapper_path = dist_dir.join(&wrapper_name); build_cargo_wrapper_cmd .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs"))) .arg("-o") @@ -79,22 +76,20 @@ pub(crate) fn build_sysroot( build_cargo_wrapper_cmd.env("BUILTIN_BACKEND", name); } spawn_and_wait(build_cargo_wrapper_cmd); - try_hard_link(wrapper_path, BIN_DIR.to_path(dirs).join(wrapper_name)); + try_hard_link(wrapper_path, dist_dir.join("bin").join(wrapper_name)); } let host = build_sysroot_for_triple( dirs, - channel, bootstrap_host_compiler.clone(), &cg_clif_dylib_path, sysroot_kind, ); - host.install_into_sysroot(&DIST_DIR.to_path(dirs)); + host.install_into_sysroot(&dist_dir); if !is_native { build_sysroot_for_triple( dirs, - channel, { let mut bootstrap_target_compiler = bootstrap_host_compiler.clone(); bootstrap_target_compiler.triple = target_triple.clone(); @@ -104,7 +99,7 @@ pub(crate) fn build_sysroot( &cg_clif_dylib_path, sysroot_kind, ) - .install_into_sysroot(&DIST_DIR.to_path(dirs)); + .install_into_sysroot(&dist_dir); } // Copy std for the host to the lib dir. This is necessary for the jit mode to find @@ -112,16 +107,13 @@ pub(crate) fn build_sysroot( for lib in host.libs { let filename = lib.file_name().unwrap().to_str().unwrap(); if filename.contains("std-") && !filename.contains(".rlib") { - try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap())); + try_hard_link(&lib, dist_dir.join("lib").join(lib.file_name().unwrap())); } } let mut target_compiler = { - let dirs: &Dirs = &dirs; - let rustc_clif = - RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif")); - let rustdoc_clif = - RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif")); + let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")); + let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")); Compiler { cargo: bootstrap_host_compiler.cargo.clone(), @@ -139,6 +131,7 @@ pub(crate) fn build_sysroot( target_compiler } +#[must_use] struct SysrootTarget { triple: String, libs: Vec, @@ -159,15 +152,13 @@ impl SysrootTarget { } } -pub(crate) static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib"); -pub(crate) static STANDARD_LIBRARY: CargoProject = +static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib"); +static STANDARD_LIBRARY: CargoProject = CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target"); -pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); +static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); -#[must_use] fn build_sysroot_for_triple( dirs: &Dirs, - channel: &str, compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, sysroot_kind: SysrootKind, @@ -176,13 +167,10 @@ fn build_sysroot_for_triple( SysrootKind::None => build_rtstartup(dirs, &compiler) .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }), SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler), - SysrootKind::Clif => { - build_clif_sysroot_for_triple(dirs, channel, compiler, cg_clif_dylib_path) - } + SysrootKind::Clif => build_clif_sysroot_for_triple(dirs, compiler, cg_clif_dylib_path), } } -#[must_use] fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); @@ -216,10 +204,8 @@ fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { target_libs } -#[must_use] fn build_clif_sysroot_for_triple( dirs: &Dirs, - channel: &str, mut compiler: Compiler, cg_clif_dylib_path: &CodegenBackend, ) -> SysrootTarget { @@ -231,12 +217,12 @@ fn build_clif_sysroot_for_triple( target_libs.libs.extend(rtstartup_target_libs.libs); } - let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel); + let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join("release"); if !config::get_bool("keep_sysroot") { // Cleanup the deps dir, but keep build scripts and the incremental cache for faster // recompilation as they are not affected by changes in cg_clif. - remove_dir_if_exists(&build_dir.join("deps")); + ensure_empty_dir(&build_dir.join("deps")); } // Build sysroot @@ -252,12 +238,12 @@ fn build_clif_sysroot_for_triple( // Necessary for MinGW to find rsbegin.o and rsend.o rustflags.push("--sysroot".to_owned()); rustflags.push(RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap().to_owned()); - if channel == "release" { - // Incremental compilation by default disables mir inlining. This leads to both a decent - // compile perf and a significant runtime perf regression. As such forcefully enable mir - // inlining. - rustflags.push("-Zinline-mir".to_owned()); - } + + // Incremental compilation by default disables mir inlining. This leads to both a decent + // compile perf and a significant runtime perf regression. As such forcefully enable mir + // inlining. + rustflags.push("-Zinline-mir".to_owned()); + if let Some(prefix) = env::var_os("CG_CLIF_STDLIB_REMAP_PATH_PREFIX") { rustflags.push("--remap-path-prefix".to_owned()); rustflags.push(format!( @@ -268,9 +254,7 @@ fn build_clif_sysroot_for_triple( } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); - if channel == "release" { - build_cmd.arg("--release"); - } + build_cmd.arg("--release"); build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128"); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); @@ -296,7 +280,10 @@ fn build_clif_sysroot_for_triple( fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { if !config::get_bool("keep_sysroot") { - crate::prepare::prepare_stdlib(dirs, &compiler.rustc); + let sysroot_src_orig = get_default_sysroot(&compiler.rustc).join("lib/rustlib/src/rust"); + assert!(sysroot_src_orig.exists()); + + apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); } if !compiler.triple.ends_with("windows-gnu") { diff --git a/build_system/main.rs b/build_system/main.rs index 9ddeda583afd1..b68ac7c09267e 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -81,7 +81,6 @@ fn main() { let mut out_dir = PathBuf::from("."); let mut download_dir = None; - let mut channel = "release"; let mut sysroot_kind = SysrootKind::Clif; let mut use_unstable_features = true; let mut frozen = false; @@ -99,7 +98,6 @@ fn main() { arg_error!("--download-dir requires argument"); }))); } - "--debug" => channel = "debug", "--sysroot" => { sysroot_kind = match args.next().as_deref() { Some("none") => SysrootKind::None, @@ -206,7 +204,6 @@ fn main() { } else { CodegenBackend::Local(build_backend::build_backend( &dirs, - channel, &bootstrap_host_compiler, use_unstable_features, )) @@ -218,7 +215,6 @@ fn main() { Command::Test => { tests::run_tests( &dirs, - channel, sysroot_kind, use_unstable_features, &skip_tests.iter().map(|test| &**test).collect::>(), @@ -234,7 +230,6 @@ fn main() { process::exit(1); } abi_cafe::run( - channel, sysroot_kind, &dirs, &cg_clif_dylib, @@ -245,7 +240,6 @@ fn main() { Command::Build => { build_sysroot::build_sysroot( &dirs, - channel, sysroot_kind, &cg_clif_dylib, &bootstrap_host_compiler, @@ -256,7 +250,6 @@ fn main() { Command::Bench => { build_sysroot::build_sysroot( &dirs, - channel, sysroot_kind, &cg_clif_dylib, &bootstrap_host_compiler, diff --git a/build_system/path.rs b/build_system/path.rs index 8572815fc55e4..35e7e81c5285d 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -1,7 +1,7 @@ use std::fs; use std::path::PathBuf; -use crate::utils::remove_dir_if_exists; +use crate::utils::ensure_empty_dir; #[derive(Debug, Clone)] pub(crate) struct Dirs { @@ -64,7 +64,6 @@ impl RelPath { pub(crate) fn ensure_fresh(&self, dirs: &Dirs) { let path = self.to_path(dirs); - remove_dir_if_exists(&path); - fs::create_dir_all(path).unwrap(); + ensure_empty_dir(&path); } } diff --git a/build_system/prepare.rs b/build_system/prepare.rs index be0bed0f4e636..b9cfcd99a7772 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -4,12 +4,8 @@ use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::Command; -use crate::build_sysroot::STDLIB_SRC; use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_default_sysroot; -use crate::utils::{ - copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait, -}; +use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait}; pub(crate) fn prepare(dirs: &Dirs) { RelPath::DOWNLOAD.ensure_exists(dirs); @@ -17,13 +13,6 @@ pub(crate) fn prepare(dirs: &Dirs) { crate::tests::REGEX_REPO.fetch(dirs); } -pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) { - let sysroot_src_orig = get_default_sysroot(rustc).join("lib/rustlib/src/rust"); - assert!(sysroot_src_orig.exists()); - - apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); -} - pub(crate) struct GitRepo { url: GitRepoUrl, rev: &'static str, @@ -119,7 +108,11 @@ impl GitRepo { match self.url { GitRepoUrl::Github { user, repo } => { - clone_repo_shallow_github(dirs, &download_dir, user, repo, self.rev); + clone_repo( + &download_dir, + &format!("https://github.com/{}/{}.git", user, repo), + self.rev, + ); } } @@ -154,7 +147,6 @@ impl GitRepo { } } -#[allow(dead_code)] fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { eprintln!("[CLONE] {}", repo); // Ignore exit code as the repo may already have been checked out @@ -171,55 +163,6 @@ fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { std::fs::remove_dir_all(download_dir.join(".git")).unwrap(); } -fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) { - if cfg!(windows) { - // Older windows doesn't have tar or curl by default. Fall back to using git. - clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev); - return; - } - - let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev); - let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev)); - let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev)); - - eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url); - - // Remove previous results if they exists - let _ = std::fs::remove_file(&archive_file); - let _ = std::fs::remove_dir_all(&archive_dir); - let _ = std::fs::remove_dir_all(&download_dir); - - // Download zip archive - let mut download_cmd = Command::new("curl"); - download_cmd - .arg("--max-time") - .arg("600") - .arg("-y") - .arg("30") - .arg("-Y") - .arg("10") - .arg("--connect-timeout") - .arg("30") - .arg("--continue-at") - .arg("-") - .arg("--location") - .arg("--output") - .arg(&archive_file) - .arg(archive_url); - retry_spawn_and_wait(5, download_cmd); - - // Unpack tar archive - let mut unpack_cmd = Command::new("tar"); - unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs)); - spawn_and_wait(unpack_cmd); - - // Rename unpacked dir to the expected name - std::fs::rename(archive_dir, &download_dir).unwrap(); - - // Cleanup - std::fs::remove_file(archive_file).unwrap(); -} - fn init_git_repo(repo_dir: &Path) { let mut git_init_cmd = git_command(repo_dir, "init"); git_init_cmd.arg("-q"); @@ -259,14 +202,8 @@ pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, ta eprintln!("[COPY] {crate_name} source"); - remove_dir_if_exists(target_dir); - fs::create_dir_all(target_dir).unwrap(); - if crate_name == "stdlib" { - fs::create_dir(target_dir.join("library")).unwrap(); - copy_dir_recursively(&source_dir.join("library"), &target_dir.join("library")); - } else { - copy_dir_recursively(source_dir, target_dir); - } + ensure_empty_dir(target_dir); + copy_dir_recursively(source_dir, target_dir); init_git_repo(target_dir); @@ -285,3 +222,22 @@ pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, ta spawn_and_wait(apply_patch_cmd); } } + +#[must_use] +fn git_command<'a>(repo_dir: impl Into>, cmd: &str) -> Command { + let mut git_cmd = Command::new("git"); + git_cmd + .arg("-c") + .arg("user.name=Dummy") + .arg("-c") + .arg("user.email=dummy@example.com") + .arg("-c") + .arg("core.autocrlf=false") + .arg("-c") + .arg("commit.gpgSign=false") + .arg(cmd); + if let Some(repo_dir) = repo_dir.into() { + git_cmd.current_dir(repo_dir); + } + git_cmd +} diff --git a/build_system/tests.rs b/build_system/tests.rs index 602f7eccf2306..fd94e80f6312e 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -117,7 +117,7 @@ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rand", ); -pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); +static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", @@ -127,12 +127,11 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "regex", ); -pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); +static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); -pub(crate) static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("coretests"); +static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("portable-simd"); -pub(crate) static PORTABLE_SIMD: CargoProject = - CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); +static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests"); @@ -230,13 +229,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ if runner.is_native { let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs); test_cmd.arg("-q"); - // FIXME remove after portable-simd update - test_cmd - .arg("--") - .arg("--skip") - .arg("core_simd::swizzle::simd_swizzle") - .arg("--skip") - .arg("core_simd::vector::Simd::lanes"); spawn_and_wait(test_cmd); } }), @@ -244,7 +236,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ pub(crate) fn run_tests( dirs: &Dirs, - channel: &str, sysroot_kind: SysrootKind, use_unstable_features: bool, skip_tests: &[&str], @@ -260,7 +251,6 @@ pub(crate) fn run_tests( if config::get_bool("testsuite.no_sysroot") && !skip_tests.contains(&"testsuite.no_sysroot") { let target_compiler = build_sysroot::build_sysroot( dirs, - channel, SysrootKind::None, cg_clif_dylib, bootstrap_host_compiler, @@ -291,7 +281,6 @@ pub(crate) fn run_tests( if run_base_sysroot || run_extended_sysroot { let target_compiler = build_sysroot::build_sysroot( dirs, - channel, sysroot_kind, cg_clif_dylib, bootstrap_host_compiler, @@ -443,7 +432,6 @@ impl<'a> TestRunner<'a> { cmd.arg("--target"); cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); - cmd.arg("-Zunstable-options"); cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); cmd @@ -458,26 +446,11 @@ impl<'a> TestRunner<'a> { } fn run_out_command(&self, name: &str, args: &[&str]) { - let mut full_cmd = vec![]; + let mut cmd = self + .target_compiler + .run_with_runner(BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name)); - // Prepend the RUN_WRAPPER's - if !self.target_compiler.runner.is_empty() { - full_cmd.extend(self.target_compiler.runner.iter().cloned()); - } - - full_cmd.push( - BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(), - ); - - for arg in args { - full_cmd.push(arg.to_string()); - } - - let mut cmd_iter = full_cmd.into_iter(); - let first = cmd_iter.next().unwrap(); - - let mut cmd = Command::new(first); - cmd.args(cmd_iter); + cmd.args(args); spawn_and_wait(cmd); } diff --git a/build_system/usage.txt b/build_system/usage.txt index f652599447bcf..5c333fe2db596 100644 --- a/build_system/usage.txt +++ b/build_system/usage.txt @@ -2,16 +2,12 @@ The build system of cg_clif. USAGE: ./y.sh prepare [--out-dir DIR] [--download-dir DIR] - ./y.sh build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] - ./y.sh test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] - ./y.sh abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] - ./y.sh bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh build [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] + ./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] OPTIONS: - --debug - Build cg_clif and the standard library in debug mode rather than release mode. - Warning: An unoptimized cg_clif is very slow. - --sysroot none|clif|llvm Which sysroot libraries to use: `none` will not include any standard library in the sysroot. @@ -43,7 +39,5 @@ REQUIREMENTS: * Rustup: By default rustup is used to install the right nightly version. If you don't want to use rustup, you can manually install the nightly version indicated by rust-toolchain.toml and point the CARGO, RUSTC and RUSTDOC env vars to the right executables. - * Git: Git is used for applying patches and on Windows for downloading test repos. - * Curl and tar (non-Windows only): Used by `./y.sh prepare` to download a single commit for - repos. Git will be used to clone the whole repo when using Windows. + * Git: Git is used for downloading test repos and applying patches. * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.sh bench`. diff --git a/build_system/utils.rs b/build_system/utils.rs index 3c4b45e02cc25..22a9487a202d6 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -1,3 +1,4 @@ +use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::{self, Command}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -59,6 +60,18 @@ impl Compiler { } } } + + pub(crate) fn run_with_runner(&self, program: impl AsRef) -> Command { + if self.runner.is_empty() { + Command::new(program) + } else { + let mut runner_iter = self.runner.iter(); + let mut cmd = Command::new(runner_iter.next().unwrap()); + cmd.args(runner_iter); + cmd.arg(program); + cmd + } + } } pub(crate) struct CargoProject { @@ -141,59 +154,6 @@ impl CargoProject { } } -#[must_use] -pub(crate) fn hyperfine_command( - warmup: u64, - runs: u64, - prepare: Option<&str>, - cmds: &[(&str, &str)], - markdown_export: &Path, -) -> Command { - let mut bench = Command::new("hyperfine"); - - bench.arg("--export-markdown").arg(markdown_export); - - if warmup != 0 { - bench.arg("--warmup").arg(warmup.to_string()); - } - - if runs != 0 { - bench.arg("--runs").arg(runs.to_string()); - } - - if let Some(prepare) = prepare { - bench.arg("--prepare").arg(prepare); - } - - for &(name, cmd) in cmds { - if name != "" { - bench.arg("-n").arg(name); - } - bench.arg(cmd); - } - - bench -} - -#[must_use] -pub(crate) fn git_command<'a>(repo_dir: impl Into>, cmd: &str) -> Command { - let mut git_cmd = Command::new("git"); - git_cmd - .arg("-c") - .arg("user.name=Dummy") - .arg("-c") - .arg("user.email=dummy@example.com") - .arg("-c") - .arg("core.autocrlf=false") - .arg("-c") - .arg("commit.gpgSign=false") - .arg(cmd); - if let Some(repo_dir) = repo_dir.into() { - git_cmd.current_dir(repo_dir); - } - git_cmd -} - #[track_caller] pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { let src = src.as_ref(); @@ -212,27 +172,33 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { } } -// Based on the retry function in rust's src/ci/shared.sh -#[track_caller] -pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) { - for i in 1..tries + 1 { - if i != 1 { - eprintln!("Command failed. Attempt {i}/{tries}:"); - } - if cmd.spawn().unwrap().wait().unwrap().success() { +/// Create the specified directory if it doesn't exist yet and delete all contents. +pub(crate) fn ensure_empty_dir(path: &Path) { + fs::create_dir_all(path).unwrap(); + let read_dir = match fs::read_dir(&path) { + Ok(read_dir) => read_dir, + Err(err) if err.kind() == io::ErrorKind::NotFound => { return; } - std::thread::sleep(std::time::Duration::from_secs(i * 5)); - } - eprintln!("The command has failed after {tries} attempts."); - process::exit(1); -} - -pub(crate) fn remove_dir_if_exists(path: &Path) { - match fs::remove_dir_all(&path) { - Ok(()) => {} - Err(err) if err.kind() == io::ErrorKind::NotFound => {} - Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()), + Err(err) => { + panic!("Failed to read contents of {path}: {err}", path = path.display()) + } + }; + for entry in read_dir { + let entry = entry.unwrap(); + if entry.file_type().unwrap().is_dir() { + match fs::remove_dir_all(entry.path()) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()), + } + } else { + match fs::remove_file(entry.path()) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()), + } + } } } diff --git a/clean_all.sh b/clean_all.sh index 19405a53d1c65..4dbd9dac94a89 100755 --- a/clean_all.sh +++ b/clean_all.sh @@ -1,9 +1,10 @@ -#!/usr/bin/env bash +#!/bin/sh set -e -rm -rf target/ build_system/target download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb +rm -rf target/ build_system/target download/ build/ dist/ # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh # FIXME remove at some point in the future +rm y.bin y.bin.dSYM y.exe y.pdb 2>/dev/null || true rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} diff --git a/example/neon.rs b/example/neon.rs index 00e437d7e546a..69ce17d3d752a 100644 --- a/example/neon.rs +++ b/example/neon.rs @@ -202,6 +202,44 @@ unsafe fn test_vqadd_u8() { assert_eq!(r, e); } +#[cfg(target_arch = "aarch64")] +unsafe fn test_vmaxq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.fmax.v4f32 + let a = f32x4::from([0., -1., 2., -3.]); + let b = f32x4::from([-4., 5., -6., 7.]); + let e = f32x4::from([0., 5., 2., 7.]); + let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vminq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.fmin.v4f32 + let a = f32x4::from([0., -1., 2., -3.]); + let b = f32x4::from([-4., 5., -6., 7.]); + let e = f32x4::from([-4., -1., -6., -3.]); + let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vaddvq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.faddv.f32.v4f32 + let a = f32x4::from([0., 1., 2., 3.]); + let e = 6f32; + let r = vaddvq_f32(transmute(a)); + assert_eq!(r, e); +} + +#[cfg(target_arch = "aarch64")] +unsafe fn test_vrndnq_f32() { + // AArch64 llvm intrinsic: llvm.aarch64.neon.frintn.v4f32 + let a = f32x4::from([0.1, -1.9, 4.5, 5.5]); + let e = f32x4::from([0., -2., 4., 6.]); + let r: f32x4 = transmute(vrndnq_f32(transmute(a))); + assert_eq!(r, e); +} + #[cfg(target_arch = "aarch64")] fn main() { unsafe { @@ -229,6 +267,11 @@ fn main() { test_vqsub_u8(); test_vqadd_u8(); + + test_vmaxq_f32(); + test_vminq_f32(); + test_vaddvq_f32(); + test_vrndnq_f32(); } } diff --git a/example/std_example.rs b/example/std_example.rs index 602452d827602..ebaa9c69c810a 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -258,6 +258,9 @@ unsafe fn test_simd() { test_mm_insert_epi16(); test_mm_shuffle_epi8(); + #[cfg(not(jit))] + test_mm_cmpestri(); + test_mm256_shuffle_epi8(); test_mm256_permute2x128_si256(); test_mm256_permutevar8x32_epi32(); @@ -429,6 +432,31 @@ unsafe fn test_mm_shuffle_epi8() { assert_eq_m128i(r, expected); } +// Currently one cannot `load` a &[u8] that is less than 16 +// in length. This makes loading strings less than 16 in length +// a bit difficult. Rather than `load` and mutate the __m128i, +// it is easier to memcpy the given string to a local slice with +// length 16 and `load` the local slice. +#[cfg(not(jit))] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +unsafe fn str_to_m128i(s: &[u8]) -> __m128i { + assert!(s.len() <= 16); + let slice = &mut [0u8; 16]; + std::ptr::copy_nonoverlapping(s.as_ptr(), slice.as_mut_ptr(), s.len()); + _mm_loadu_si128(slice.as_ptr() as *const _) +} + +#[cfg(not(jit))] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +unsafe fn test_mm_cmpestri() { + let a = str_to_m128i(b"bar - garbage"); + let b = str_to_m128i(b"foobar"); + let i = _mm_cmpestri::<_SIDD_CMP_EQUAL_ORDERED>(a, 3, b, 6); + assert_eq!(3, i); +} + #[cfg(target_arch = "x86_64")] #[target_feature(enable = "avx2")] unsafe fn test_mm256_shuffle_epi8() { diff --git a/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch b/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch new file mode 100644 index 0000000000000..b1fd6224632be --- /dev/null +++ b/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch @@ -0,0 +1,26 @@ +From 5489384bc265e9e6fc2efaa63d93a4d51ebec2f5 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Thu, 22 Aug 2024 19:22:58 +0000 +Subject: [PATCH] Disable broken reduce_sum test + +It was broken by an upstream change to the .sum() implementation on +float iterators. +--- + crates/core_simd/tests/ops_macros.rs | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs +index aa565a1..5e6ac41 100644 +--- a/crates/core_simd/tests/ops_macros.rs ++++ b/crates/core_simd/tests/ops_macros.rs +@@ -646,6 +646,7 @@ macro_rules! impl_float_tests { + } + + fn reduce_sum() { ++ return; + test_helpers::test_1(&|x| { + test_helpers::prop_assert_biteq! ( + Vector::::from_array(x).reduce_sum(), +-- +2.34.1 + diff --git a/patches/0022-coretests-Disable-not-compiling-tests.patch b/patches/0022-coretests-Disable-not-compiling-tests.patch index 8c404956bcc20..5117b04fd3447 100644 --- a/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644 @@ -1,3 +1,4 @@ +#![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(bootstrap, feature(const_mut_refs))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] -- 2.21.0 (Apple Git-122) diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-coretests-128bit-atomic-operations.patch index d579c9588f08a..efd721d9df885 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-coretests-128bit-atomic-operations.patch @@ -14,14 +14,13 @@ diff --git a/lib.rs b/lib.rs index 1e336bf..35e6f54 100644 --- a/lib.rs +++ b/lib.rs -@@ -1,7 +1,6 @@ +@@ -1,6 +1,5 @@ #![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(bootstrap, feature(const_mut_refs))] -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] - #![feature(array_chunks)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/patches/0028-coretests-Disable-long-running-tests.patch b/patches/0028-coretests-Disable-long-running-tests.patch index 440177018f428..d7204add7a788 100644 --- a/patches/0028-coretests-Disable-long-running-tests.patch +++ b/patches/0028-coretests-Disable-long-running-tests.patch @@ -43,6 +43,26 @@ index 8402833..84592e0 100644 #[test] fn test_slice_from_ptr_range() { +diff --git a/lazy.rs b/lazy.rs +index 711511e..49c8d78 100644 +--- a/lazy.rs ++++ b/lazy.rs +@@ -113,6 +113,7 @@ fn lazy_type_inference() { + let _ = LazyCell::new(|| ()); + } + ++/* + #[test] + #[should_panic = "LazyCell instance has previously been poisoned"] + fn lazy_force_mut_panic() { +@@ -123,6 +124,7 @@ fn lazy_force_mut_panic() { + .unwrap_err(); + let _ = &*lazy; + } ++*/ + + #[test] + fn lazy_force_mut() { -- 2.26.2.7.g19db9cfb68 diff --git a/rust-toolchain b/rust-toolchain index 96c467e091cff..651770be3775d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-09" +channel = "nightly-2024-09-23" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 684a5d0729355..2f13b0b9cb834 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -25,6 +25,9 @@ git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ cat > config.toml <) { + + let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js"); + +- if mode == "run-make" { +- let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); +- cmd.arg("--cargo-path").arg(cargo); +- } +- + // Avoid depending on rustdoc when we don't need it. + if mode == "rustdoc" + || mode == "run-make" +diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs +index 414f9f3a7f1..5c18179b6fe 100644 +--- a/src/tools/compiletest/src/common.rs ++++ b/src/tools/compiletest/src/common.rs +@@ -183,9 +183,6 @@ pub struct Config { + /// The rustc executable. + pub rustc_path: PathBuf, + +- /// The cargo executable. +- pub cargo_path: Option, +- + /// The rustdoc executable. + pub rustdoc_path: Option, + +diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs +index 3339116d542..250b5084d13 100644 +--- a/src/tools/compiletest/src/lib.rs ++++ b/src/tools/compiletest/src/lib.rs +@@ -47,7 +47,6 @@ pub fn parse_config(args: Vec) -> Config { + opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") +- .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") + .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") +@@ -261,7 +260,6 @@ fn make_absolute(path: PathBuf) -> PathBuf { + compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), + rustc_path: opt_path(matches, "rustc-path"), +- cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), + rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), + coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), + python: matches.opt_str("python").unwrap(), +@@ -366,7 +364,6 @@ pub fn log_config(config: &Config) { + logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); + logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); +- logv(c, format!("cargo_path: {:?}", config.cargo_path)); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); +diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs +index 75fe6a6baaf..852568ae925 100644 +--- a/src/tools/compiletest/src/runtest/run_make.rs ++++ b/src/tools/compiletest/src/runtest/run_make.rs +@@ -61,10 +61,6 @@ fn run_rmake_legacy_test(&self) { + .env_remove("MFLAGS") + .env_remove("CARGO_MAKEFLAGS"); + +- if let Some(ref cargo) = self.config.cargo_path { +- cmd.env("CARGO", cwd.join(cargo)); +- } +- + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", cwd.join(rustdoc)); + } +@@ -413,10 +409,6 @@ fn run_rmake_v2_test(&self) { + // through a specific CI runner). + .env("LLVM_COMPONENTS", &self.config.llvm_components); + +- if let Some(ref cargo) = self.config.cargo_path { +- cmd.env("CARGO", source_root.join(cargo)); +- } +- + if let Some(ref rustdoc) = self.config.rustdoc_path { + cmd.env("RUSTDOC", source_root.join(rustdoc)); + } EOF echo "[TEST] rustc test suite" diff --git a/src/abi/mod.rs b/src/abi/mod.rs index cb74c59046be7..892ec3e95855e 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -508,7 +508,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( let nop_inst = fx.bcx.ins().nop(); fx.add_comment( nop_inst, - format!("virtual call; self arg pass mode: {:?}", fn_abi.args[0]), + with_no_trimmed_paths!(format!( + "virtual call; self arg pass mode: {:?}", + fn_abi.args[0] + )), ); } diff --git a/src/constant.rs b/src/constant.rs index 8964230d6e2c8..6ba6a64c54486 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -490,6 +490,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } /// Used only for intrinsic implementations that need a compile-time constant +/// +/// All uses of this function are a bug inside stdarch. [`eval_mir_constant`] +/// should be used everywhere, but for some vendor intrinsics stdarch forgets +/// to wrap the immediate argument in `const {}`, necesitating this hack to get +/// the correct value at compile time instead. pub(crate) fn mir_operand_get_const_val<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, operand: &Operand<'tcx>, diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index f0fb18608e072..39f6763d9f2cb 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -91,6 +91,44 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( ); } + _ if intrinsic.starts_with("llvm.aarch64.neon.fmax.v") => { + intrinsic_args!(fx, args => (x, y); intrinsic); + + simd_pair_for_each_lane( + fx, + x, + y, + ret, + &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| fx.bcx.ins().fmax(x_lane, y_lane), + ); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.fmin.v") => { + intrinsic_args!(fx, args => (x, y); intrinsic); + + simd_pair_for_each_lane( + fx, + x, + y, + ret, + &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| fx.bcx.ins().fmin(x_lane, y_lane), + ); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.faddv.f32.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().fadd(a, b)); + } + + _ if intrinsic.starts_with("llvm.aarch64.neon.frintn.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().nearest(lane) + }); + } + _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => { intrinsic_args!(fx, args => (v); intrinsic); diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 0740c84a53401..19e5adc253854 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -600,9 +600,11 @@ fn codegen_regular_intrinsic_call<'tcx>( sym::ptr_mask => { intrinsic_args!(fx, args => (ptr, mask); intrinsic); + let ptr_layout = ptr.layout(); let ptr = ptr.load_scalar(fx); let mask = mask.load_scalar(fx); - fx.bcx.ins().band(ptr, mask); + let res = fx.bcx.ins().band(ptr, mask); + ret.write_cvalue(fx, CValue::by_val(res, ptr_layout)); } sym::write_bytes | sym::volatile_set_memory => { diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index f2bdf24d8abd9..ff4b0e847af6a 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -181,11 +181,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // Make sure this is actually a SIMD vector. let idx_ty = fx.monomorphize(idx.node.ty(fx.mir, fx.tcx)); - let n: u16 = if idx_ty.is_simd() - && matches!(idx_ty.simd_size_and_type(fx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) + if !idx_ty.is_simd() + || !matches!(idx_ty.simd_size_and_type(fx.tcx).1.kind(), ty::Uint(ty::UintTy::U32)) { - idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap() - } else { fx.tcx.dcx().span_err( span, format!("simd_shuffle index must be a SIMD vector of `u32`, got `{}`", idx_ty), @@ -194,6 +192,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); return; }; + let n: u16 = idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); @@ -268,10 +267,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let val = codegen_operand(fx, &val.node); // FIXME validate - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, &idx.node) - { - idx_const + let idx_const = if let Some(idx_const) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, idx_const).0.try_to_scalar_int().unwrap() } else { fx.tcx.dcx().span_fatal(span, "Index argument for `simd_insert` is not a constant"); }; @@ -304,22 +301,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - let idx_const = if let Some(idx_const) = - crate::constant::mir_operand_get_const_val(fx, &idx.node) - { - idx_const + let idx_const = if let Some(idx_const) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, idx_const).0.try_to_scalar_int().unwrap() } else { - fx.tcx.dcx().span_warn(span, "Index argument for `simd_extract` is not a constant"); - let trap_block = fx.bcx.create_block(); - let true_ = fx.bcx.ins().iconst(types::I8, 1); - let ret_block = fx.get_block(target); - fx.bcx.ins().brif(true_, trap_block, &[], ret_block, &[]); - fx.bcx.switch_to_block(trap_block); - crate::trap::trap_unimplemented( - fx, - "Index argument for `simd_extract` is not a constant", - ); - return; + fx.tcx + .dcx() + .span_fatal(span, "Index argument for `simd_extract` is not a constant"); }; let idx = idx_const.to_u32(); @@ -574,9 +561,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (sym::simd_round, types::F64) => "round", _ => unreachable!("{:?}", intrinsic), }; - fx.lib_call(name, vec![AbiParam::new(lane_ty)], vec![AbiParam::new(lane_ty)], &[ - lane, - ])[0] + fx.lib_call( + name, + vec![AbiParam::new(lane_ty)], + vec![AbiParam::new(lane_ty)], + &[lane], + )[0] }); } diff --git a/test.sh b/test.sh index 6357eebf02696..6c07c512ef294 100755 --- a/test.sh +++ b/test.sh @@ -1,2 +1,2 @@ -#!/usr/bin/env bash +#!/bin/sh exec ./y.sh test "$@" diff --git a/y.sh b/y.sh index b9152d2cc6de0..a70d457341b93 100755 --- a/y.sh +++ b/y.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh set -e echo "[BUILD] build system" 1>&2 From f3ae4237ab90e3c3e8a135799e71e3ab425b7a58 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Sep 2024 19:02:30 +0000 Subject: [PATCH 0011/1110] Revert change to apply_patches to fix panic --- build_system/prepare.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build_system/prepare.rs b/build_system/prepare.rs index b9cfcd99a7772..30bd7ae26a186 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -203,7 +203,12 @@ pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, ta eprintln!("[COPY] {crate_name} source"); ensure_empty_dir(target_dir); - copy_dir_recursively(source_dir, target_dir); + if crate_name == "stdlib" { + fs::create_dir(target_dir.join("library")).unwrap(); + copy_dir_recursively(&source_dir.join("library"), &target_dir.join("library")); + } else { + copy_dir_recursively(source_dir, target_dir); + } init_git_repo(target_dir); From 9d8572d33b22b0e045a0f485eb5c11ae4af12a30 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:28:15 +0000 Subject: [PATCH 0012/1110] Rustfmt --- build_system/build_sysroot.rs | 4 ++-- src/intrinsics/simd.rs | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 6a4f2a6c72c52..82558999aface 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -6,9 +6,9 @@ use crate::path::{Dirs, RelPath}; use crate::prepare::apply_patches; use crate::rustc_info::{get_default_sysroot, get_file_name}; use crate::utils::{ - ensure_empty_dir, spawn_and_wait, try_hard_link, CargoProject, Compiler, LogGroup, + CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait, try_hard_link, }; -use crate::{config, CodegenBackend, SysrootKind}; +use crate::{CodegenBackend, SysrootKind, config}; pub(crate) fn build_sysroot( dirs: &Dirs, diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index ff4b0e847af6a..cbe411d78d5fd 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -561,12 +561,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (sym::simd_round, types::F64) => "round", _ => unreachable!("{:?}", intrinsic), }; - fx.lib_call( - name, - vec![AbiParam::new(lane_ty)], - vec![AbiParam::new(lane_ty)], - &[lane], - )[0] + fx.lib_call(name, vec![AbiParam::new(lane_ty)], vec![AbiParam::new(lane_ty)], &[ + lane, + ])[0] }); } From 631ab21ff01472c629c4bb5bb40338b0f04e8838 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 22 Sep 2024 20:00:01 -0400 Subject: [PATCH 0013/1110] Check vtable projections for validity in miri --- src/constant.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/constant.rs b/src/constant.rs index 6ba6a64c54486..ab78584332a05 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -161,13 +161,13 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty, dyn_ty) => { let data_id = data_id_for_vtable( fx.tcx, &mut fx.constants_cx, fx.module, ty, - trait_ref, + dyn_ty.principal(), ); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); @@ -456,8 +456,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } - GlobalAlloc::VTable(ty, trait_ref) => { - data_id_for_vtable(tcx, cx, module, ty, trait_ref) + GlobalAlloc::VTable(ty, dyn_ty) => { + data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal()) } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) From b2fd8a0192f6a69a4fb969ab3d005b577a524371 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 19 Sep 2024 15:00:30 -0700 Subject: [PATCH 0014/1110] Test fixing raw-dylib --- compiler/rustc_codegen_gcc/src/archive.rs | 3 +- compiler/rustc_codegen_llvm/src/callee.rs | 25 +++++--- compiler/rustc_codegen_llvm/src/consts.rs | 10 +-- .../rustc_codegen_ssa/src/back/archive.rs | 63 +++++++++++-------- compiler/rustc_codegen_ssa/src/back/link.rs | 35 ++++++++--- compiler/rustc_codegen_ssa/src/common.rs | 9 ++- compiler/rustc_session/src/cstore.rs | 5 ++ 7 files changed, 95 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 0cee05f1cea38..82e98370b376b 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -2,6 +2,7 @@ use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, + ImportLibraryItem, }; use rustc_session::Session; @@ -16,7 +17,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, _sess: &Session, _lib_name: &str, - _import_name_and_ordinal_vector: Vec<(String, Option)>, + _items: Vec, _output_path: &Path, ) { unimplemented!("creating dll imports is not yet supported"); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 949fd1bc124f5..db4e1bae94229 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -49,6 +49,22 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let llfn = if tcx.sess.target.arch == "x86" && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym) { + // When calling functions in generated import libraries, MSVC needs + // the fully decorated name (as would have been in the declaring + // object file), but MinGW wants the name as exported (as would be + // in the def file) which may be missing decorations. + let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&tcx.sess.target); + let llfn = cx.declare_fn( + &common::i686_decorated_name( + dllimport, + mingw_gnu_toolchain, + true, + !mingw_gnu_toolchain, + ), + fn_abi, + Some(instance), + ); + // Fix for https://github.com/rust-lang/rust/issues/104453 // On x86 Windows, LLVM uses 'L' as the prefix for any private // global symbols, so when we create an undecorated function symbol @@ -60,15 +76,6 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // LLVM will prefix the name with `__imp_`. Ideally, we'd like the // existing logic below to set the Storage Class, but it has an // exemption for MinGW for backwards compatibility. - let llfn = cx.declare_fn( - &common::i686_decorated_name( - dllimport, - common::is_mingw_gnu_toolchain(&tcx.sess.target), - true, - ), - fn_abi, - Some(instance), - ); unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c3b1676f77e75..dc86ef22e37da 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -196,16 +196,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( g2 } } else if cx.tcx.sess.target.arch == "x86" + && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) { - cx.declare_global( - &common::i686_decorated_name( - dllimport, - common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), - true, - ), - llty, - ) + cx.declare_global(&common::i686_decorated_name(dllimport, true, true, false), llty) } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index a665f5c93060d..eb714853a4a0a 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -26,6 +26,35 @@ use crate::errors::{ DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, }; +/// An item to be included in an import library. +/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`. +pub struct ImportLibraryItem { + /// The name to be exported. + pub name: String, + /// The ordinal to be exported, if any. + pub ordinal: Option, + /// The original, decorated name if `name` is not decorated. + pub symbol_name: Option, + /// True if this is a data export, false if it is a function export. + pub is_data: bool, +} + +impl From for COFFShortExport { + fn from(item: ImportLibraryItem) -> Self { + COFFShortExport { + name: item.name, + ext_name: None, + symbol_name: item.symbol_name, + alias_target: None, + ordinal: item.ordinal.unwrap_or(0), + noname: item.ordinal.is_some(), + data: item.is_data, + private: false, + constant: false, + } + } +} + pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box; @@ -38,7 +67,7 @@ pub trait ArchiveBuilderBuilder { &self, sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option)>, + items: Vec, output_path: &Path, ) { if common::is_mingw_gnu_toolchain(&sess.target) { @@ -47,21 +76,16 @@ pub trait ArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - create_mingw_dll_import_lib( - sess, - lib_name, - import_name_and_ordinal_vector, - output_path, - ); + create_mingw_dll_import_lib(sess, lib_name, items, output_path); } else { trace!("creating import library"); trace!(" dll_name {:#?}", lib_name); trace!(" output_path {}", output_path.display()); trace!( " import names: {}", - import_name_and_ordinal_vector + items .iter() - .map(|(name, _ordinal)| name.clone()) + .map(|ImportLibraryItem { name, .. }| name.clone()) .collect::>() .join(", "), ); @@ -79,20 +103,7 @@ pub trait ArchiveBuilderBuilder { .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }), }; - let exports = import_name_and_ordinal_vector - .iter() - .map(|(name, ordinal)| COFFShortExport { - name: name.to_string(), - ext_name: None, - symbol_name: None, - alias_target: None, - ordinal: ordinal.unwrap_or(0), - noname: ordinal.is_some(), - data: false, - private: false, - constant: false, - }) - .collect::>(); + let exports = items.into_iter().map(Into::into).collect::>(); let machine = match &*sess.target.arch { "x86_64" => MachineTypes::AMD64, "x86" => MachineTypes::I386, @@ -160,16 +171,16 @@ pub trait ArchiveBuilderBuilder { fn create_mingw_dll_import_lib( sess: &Session, lib_name: &str, - import_name_and_ordinal_vector: Vec<(String, Option)>, + items: Vec, output_path: &Path, ) { let def_file_path = output_path.with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", - import_name_and_ordinal_vector + items .into_iter() - .map(|(name, ordinal)| { + .map(|ImportLibraryItem { name, ordinal, .. }| { match ordinal { Some(n) => format!("{name} @{n} NONAME"), None => name, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8b855bd0dd568..5fd6a2553ee45 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use rustc_target::spec::{ use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; -use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; +use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{create_wrapper_file, MetadataPosition}; @@ -498,16 +498,35 @@ fn create_dll_import_libs<'a>( let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); - let import_name_and_ordinal_vector: Vec<(String, Option)> = raw_dylib_imports + let items: Vec = raw_dylib_imports .iter() .map(|import: &DllImport| { if sess.target.arch == "x86" { - ( - common::i686_decorated_name(import, mingw_gnu_toolchain, false), - import.ordinal(), - ) + ImportLibraryItem { + name: common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + false, + ), + ordinal: import.ordinal(), + symbol_name: import.is_missing_decorations().then(|| { + common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + true, + ) + }), + is_data: !import.is_fn, + } } else { - (import.name.to_string(), import.ordinal()) + ImportLibraryItem { + name: import.name.to_string(), + ordinal: import.ordinal(), + symbol_name: None, + is_data: !import.is_fn, + } } }) .collect(); @@ -515,7 +534,7 @@ fn create_dll_import_libs<'a>( archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, - import_name_and_ordinal_vector, + items, &output_path, ); diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 582a2a87e4867..965bd34ac147b 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -187,12 +187,15 @@ pub fn i686_decorated_name( dll_import: &DllImport, mingw: bool, disable_name_mangling: bool, + force_fully_decorated: bool, ) -> String { let name = dll_import.name.as_str(); - let (add_prefix, add_suffix) = match dll_import.import_name_type { - Some(PeImportNameType::NoPrefix) => (false, true), - Some(PeImportNameType::Undecorated) => (false, false), + let (add_prefix, add_suffix) = match (force_fully_decorated, dll_import.import_name_type) { + // No prefix is a bit weird, in that LLVM/ar_archive_writer won't emit it, so we will + // ignore `force_fully_decorated` and always partially decorate it. + (_, Some(PeImportNameType::NoPrefix)) => (false, true), + (false, Some(PeImportNameType::Undecorated)) => (false, false), _ => (true, true), }; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index da7a82fee94d0..16432095acc2f 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -130,6 +130,11 @@ impl DllImport { None } } + + pub fn is_missing_decorations(&self) -> bool { + self.import_name_type == Some(PeImportNameType::Undecorated) + || self.import_name_type == Some(PeImportNameType::NoPrefix) + } } /// Calling convention for a function defined in an external library. From 1efad223399646cef0b5e3fd53da3b248804260f Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 15 Sep 2024 16:47:42 +0200 Subject: [PATCH 0015/1110] unify dyn* coercions with other pointer coercions --- src/base.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index dc342e151f33c..876466e79bc07 100644 --- a/src/base.rs +++ b/src/base.rs @@ -770,7 +770,11 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } - Rvalue::Cast(CastKind::DynStar, ref operand, _) => { + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::DynStar), + ref operand, + _, + ) => { let operand = codegen_operand(fx, operand); crate::unsize::coerce_dyn_star(fx, operand, lval); } From 26c4893ae6a6bd5d611fd6c7b3c803a720138d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Tue, 24 Sep 2024 22:40:29 +0200 Subject: [PATCH 0016/1110] Mark 'get_mut' and 'set_position' in 'std::io::Cursor' as const; --- library/std/src/io/cursor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 9f913eae09544..fbfdb4fa02323 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -153,7 +153,8 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -200,7 +201,8 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } } From 25b66d80911b8c41feef25bac7c8a3c2aa14ebdd Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 15 Sep 2024 19:35:06 +0200 Subject: [PATCH 0017/1110] be even more precise about "cast" vs "coercion" --- src/base.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/base.rs b/src/base.rs index 876466e79bc07..1ce0aacab4998 100644 --- a/src/base.rs +++ b/src/base.rs @@ -652,7 +652,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, res); } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _), ref operand, to_ty, ) => { @@ -677,7 +677,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _), ref operand, to_ty, ) => { @@ -688,6 +688,7 @@ fn codegen_stmt<'tcx>( Rvalue::Cast( CastKind::PointerCoercion( PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + _, ), .., ) => { @@ -741,7 +742,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _), ref operand, _to_ty, ) => { @@ -763,7 +764,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), + CastKind::PointerCoercion(PointerCoercion::Unsize, _), ref operand, _to_ty, ) => { @@ -771,7 +772,7 @@ fn codegen_stmt<'tcx>( crate::unsize::coerce_unsized_into(fx, operand, lval); } Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::DynStar), + CastKind::PointerCoercion(PointerCoercion::DynStar, _), ref operand, _, ) => { From 6fdc133daad5ea1a2fccd460fd3b65a715f0f272 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Sep 2024 13:52:02 -0400 Subject: [PATCH 0018/1110] Add a debug assertion in codegen that unsize casts of the same principal trait def id are truly NOPs --- src/unsize.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/unsize.rs b/src/unsize.rs index 8cfe93b4d9c91..339628053a953 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -34,7 +34,22 @@ pub(crate) fn unsized_info<'tcx>( 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() { - // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. + // Codegen takes advantage of the additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. If we, for + // some reason, were to relax the `Unsize` trait, it could become + // unsound, so let's assert here that the trait refs are *equal*. + // + // We can use `assert_eq` because the binders should have been anonymized, + // and because higher-ranked equality now requires the binders are equal. + debug_assert_eq!( + data_a.principal(), + data_b.principal(), + "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" + ); return old_info; } From 62026c32288f86b4337dcf17bf4fabd15a140a92 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:30:28 +0200 Subject: [PATCH 0019/1110] Add units/unit prefixes of frequency to doc-valid-idents --- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 1 + tests/ui/doc/doc-fixable.fixed | 1 + tests/ui/doc/doc-fixable.rs | 1 + tests/ui/doc/doc-fixable.stderr | 44 ++++++++++++++++----------------- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 91159bc79c511..6d7420c12ec3b 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 757620341ccc1..6ed3221c31f87 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -17,6 +17,7 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "MHz", "GHz", "THz", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index edfffe8fcfe36..c2e4a124d2ae8 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -54,6 +54,7 @@ fn test_units() { /// This tests allowed identifiers. /// KiB MiB GiB TiB PiB EiB +/// MHz GHz THz /// AccessKit /// CoreFoundation CoreGraphics CoreText /// Direct2D Direct3D DirectWrite DirectX diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 3c0f6913e3289..de71cf73ffe81 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -54,6 +54,7 @@ fn test_units() { /// This tests allowed identifiers. /// KiB MiB GiB TiB PiB EiB +/// MHz GHz THz /// AccessKit /// CoreFoundation CoreGraphics CoreText /// Direct2D Direct3D DirectWrite DirectX diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index 67c0464149c6e..27a04e4b55830 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -133,7 +133,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:78:5 + --> tests/ui/doc/doc-fixable.rs:79:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:95:5 + --> tests/ui/doc/doc-fixable.rs:96:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:103:8 + --> tests/ui/doc/doc-fixable.rs:104:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | /// ## `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:106:7 + --> tests/ui/doc/doc-fixable.rs:107:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | /// # `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:108:22 + --> tests/ui/doc/doc-fixable.rs:109:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL | /// Not a title #897 `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:109:5 + --> tests/ui/doc/doc-fixable.rs:110:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:116:5 + --> tests/ui/doc/doc-fixable.rs:117:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +210,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:129:5 + --> tests/ui/doc/doc-fixable.rs:130:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +221,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:140:43 + --> tests/ui/doc/doc-fixable.rs:141:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -232,7 +232,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:145:5 + --> tests/ui/doc/doc-fixable.rs:146:5 | LL | And BarQuz too. | ^^^^^^ @@ -243,7 +243,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:146:1 + --> tests/ui/doc/doc-fixable.rs:147:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +254,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:151:43 + --> tests/ui/doc/doc-fixable.rs:152:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -265,7 +265,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:156:5 + --> tests/ui/doc/doc-fixable.rs:157:5 | LL | And BarQuz too. | ^^^^^^ @@ -276,7 +276,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:157:1 + --> tests/ui/doc/doc-fixable.rs:158:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -287,7 +287,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:168:5 + --> tests/ui/doc/doc-fixable.rs:169:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -298,7 +298,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:187:22 + --> tests/ui/doc/doc-fixable.rs:188:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -309,7 +309,7 @@ LL | /// An iterator over `mycrate::Collection`'s values. | ~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:211:34 + --> tests/ui/doc/doc-fixable.rs:212:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -320,7 +320,7 @@ LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | ~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:234:22 + --> tests/ui/doc/doc-fixable.rs:235:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -331,7 +331,7 @@ LL | /// There is no try (`do()` or do_not()). | ~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:234:30 + --> tests/ui/doc/doc-fixable.rs:235:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -342,7 +342,7 @@ LL | /// There is no try (do() or `do_not()`). | ~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:237:5 + --> tests/ui/doc/doc-fixable.rs:238:5 | LL | /// ABes | ^^^^ @@ -353,7 +353,7 @@ LL | /// `ABes` | ~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:243:9 + --> tests/ui/doc/doc-fixable.rs:244:9 | LL | /// foo() | ^^^^^ @@ -364,7 +364,7 @@ LL | /// `foo()` | ~~~~~~~ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:247:5 + --> tests/ui/doc/doc-fixable.rs:248:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` From eccda6954433ed5f5d83a571857f5f15aac4c876 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:41:40 +0000 Subject: [PATCH 0020/1110] Rustup to rustc 1.83.0-nightly (9e394f551 2024-09-25) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 651770be3775d..093f5bdc4dae0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-09-23" +channel = "nightly-2024-09-26" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 764f1ba5cd6c9eccf456748c39b26cbf78157cda Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:54:35 +0000 Subject: [PATCH 0021/1110] Fix running rustc tests --- scripts/test_rustc_tests.sh | 84 ------------------------------------- 1 file changed, 84 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 93512f82c8bf7..7c38792a6034f 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -180,90 +180,6 @@ index 9607ff02f96..b7d97caf9a2 100644 Self { cmd } } -diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs -index 2047345d78a..a7e9352bb1c 100644 ---- a/src/bootstrap/src/core/build_steps/test.rs -+++ b/src/bootstrap/src/core/build_steps/test.rs -@@ -1733,11 +1733,6 @@ fn run(self, builder: &Builder<'_>) { - - let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js"); - -- if mode == "run-make" { -- let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); -- cmd.arg("--cargo-path").arg(cargo); -- } -- - // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" - || mode == "run-make" -diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs -index 414f9f3a7f1..5c18179b6fe 100644 ---- a/src/tools/compiletest/src/common.rs -+++ b/src/tools/compiletest/src/common.rs -@@ -183,9 +183,6 @@ pub struct Config { - /// The rustc executable. - pub rustc_path: PathBuf, - -- /// The cargo executable. -- pub cargo_path: Option, -- - /// The rustdoc executable. - pub rustdoc_path: Option, - -diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs -index 3339116d542..250b5084d13 100644 ---- a/src/tools/compiletest/src/lib.rs -+++ b/src/tools/compiletest/src/lib.rs -@@ -47,7 +47,6 @@ pub fn parse_config(args: Vec) -> Config { - opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") - .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") - .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") -- .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") - .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") - .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") - .reqopt("", "python", "path to python to use for doc tests", "PATH") -@@ -261,7 +260,6 @@ fn make_absolute(path: PathBuf) -> PathBuf { - compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), - run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), - rustc_path: opt_path(matches, "rustc-path"), -- cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), - python: matches.opt_str("python").unwrap(), -@@ -366,7 +364,6 @@ pub fn log_config(config: &Config) { - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); -- logv(c, format!("cargo_path: {:?}", config.cargo_path)); - logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("src_base: {:?}", config.src_base.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); -diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs -index 75fe6a6baaf..852568ae925 100644 ---- a/src/tools/compiletest/src/runtest/run_make.rs -+++ b/src/tools/compiletest/src/runtest/run_make.rs -@@ -61,10 +61,6 @@ fn run_rmake_legacy_test(&self) { - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); - -- if let Some(ref cargo) = self.config.cargo_path { -- cmd.env("CARGO", cwd.join(cargo)); -- } -- - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); - } -@@ -413,10 +409,6 @@ fn run_rmake_v2_test(&self) { - // through a specific CI runner). - .env("LLVM_COMPONENTS", &self.config.llvm_components); - -- if let Some(ref cargo) = self.config.cargo_path { -- cmd.env("CARGO", source_root.join(cargo)); -- } -- - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", source_root.join(rustdoc)); - } EOF echo "[TEST] rustc test suite" From 9b31c68c0eaefe3257703101b2cc866c69d24fb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2024 07:32:08 +0200 Subject: [PATCH 0022/1110] fix cranelift CI --- patches/0027-stdlib-128bit-atomic-operations.patch | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/patches/0027-stdlib-128bit-atomic-operations.patch b/patches/0027-stdlib-128bit-atomic-operations.patch index a3f370af91699..646928893e96a 100644 --- a/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/patches/0027-stdlib-128bit-atomic-operations.patch @@ -82,19 +82,6 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { ( $($target_pointer_width:literal $align:literal)* ) => { $( -diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs -index 58b9ba4..91bbd0a 100644 ---- a/library/core/src/cell.rs -+++ b/library/core/src/cell.rs -@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! { - u32 "32" - i64 "64" - u64 "64" -- i128 "128" -- u128 "128" - isize "ptr" - usize "ptr" - } -- 2.26.2.7.g19db9cfb68 From d10a16ae409f5bc0f337415a5ba9b497ac0931c7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Sep 2024 14:16:05 -0400 Subject: [PATCH 0023/1110] Relax a debug assertion in codegen --- src/unsize.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/unsize.rs b/src/unsize.rs index 339628053a953..5c297ebfadbfd 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -2,6 +2,7 @@ //! //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` +use rustc_codegen_ssa::base::validate_trivial_unsize; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use crate::base::codegen_panic_nounwind; @@ -34,20 +35,8 @@ pub(crate) fn unsized_info<'tcx>( 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() { - // Codegen takes advantage of the additional assumption, where if the - // principal trait def id of what's being casted doesn't change, - // then we don't need to adjust the vtable at all. This - // corresponds to the fact that `dyn Tr: Unsize>` - // requires that `A = B`; we don't allow *upcasting* objects - // between the same trait with different args. If we, for - // some reason, were to relax the `Unsize` trait, it could become - // unsound, so let's assert here that the trait refs are *equal*. - // - // We can use `assert_eq` because the binders should have been anonymized, - // and because higher-ranked equality now requires the binders are equal. - debug_assert_eq!( - data_a.principal(), - data_b.principal(), + debug_assert!( + validate_trivial_unsize(fx.tcx, data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" ); return old_info; From 743a2e47acd141e0195972d3beb2fec6fa81a796 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:38:33 +0000 Subject: [PATCH 0024/1110] Update to Cranelift 0.112.0 --- Cargo.lock | 99 +++++++++++++++++++++++++++++------------------------- Cargo.toml | 12 +++---- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c2ca95b075ca..a4b9d958b3577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b80c3a50b9c4c7e5b5f73c0ed746687774fc9e36ef652b110da8daebf0c6e0e6" +checksum = "a6e376bd92bddd03dcfc443b14382611cae5d10012aa0b1628bbf18bb73f12f7" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38778758c2ca918b05acb2199134e0c561fb577c50574259b26190b6c2d95ded" +checksum = "45ecbe07f25a8100e5077933516200e97808f1d7196b5a073edb85fa08fde32e" [[package]] name = "cranelift-codegen" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58258667ad10e468bfc13a8d620f50dfcd4bb35d668123e97defa2549b9ad397" +checksum = "bc60913f32c1de18538c28bef74b8c87cf16de7841a1b0956fcf01b23237853a" dependencies = [ "bumpalo", "cranelift-bforest", @@ -74,8 +74,9 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.5", + "hashbrown", "log", + "pulley-interpreter", "regalloc2", "rustc-hash", "smallvec", @@ -84,42 +85,42 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043f0b702e529dcb07ff92bd7d40e7d5317b5493595172c5eb0983343751ee06" +checksum = "bae009e7822f47aa55e7dcef846ccf3aa4eb102ca6b4bcb8a44b36f3f49aa85c" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7763578888ab53eca5ce7da141953f828e82c2bfadcffc106d10d1866094ffbb" +checksum = "0c78f01a852536c68e34444450f845ed6e0782a1f047f85397fe460b8fbce8f1" [[package]] name = "cranelift-control" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db15f08c05df570f11e8ab33cb1ec449a64b37c8a3498377b77650bef33d8b" +checksum = "7a061b22e00a9e36b31f2660dfb05a9617b7775bd54b79754d3bb75a990dac06" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5289cdb399381a27e7bbfa1b42185916007c3d49aeef70b1d01cb4caa8010130" +checksum = "95e2b261a3e74ae42f4e606906d5ffa44ee2684e8b1ae23bdf75d21908dc9233" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ba8ab24eb9470477e98ddfa3c799a649ac5a0d9a2042868c4c952133c234e8" +checksum = "fe14abba0e6bab42aca0f9ce757f96880f9187e88bc6cb975ed6acd8a42f7770" dependencies = [ "cranelift-codegen", "log", @@ -129,15 +130,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b72a3c5c166a70426dcb209bdd0bb71a787c1ea76023dc0974fbabca770e8f9" +checksum = "311d91ae72b37d4262b51217baf8c9e01f1afd5148931468da1fdb7e9d011347" [[package]] name = "cranelift-jit" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df32578a47582e49b4fc1f9a5786839d9be1fedaa9f00bea7612c54425663c6b" +checksum = "1b8ea36cb2f092c71300eb1ffdb30b7e301fdc3c00479aabe36036bac53c5a5a" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +156,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96094a758cdb543c9143f70817cd31069fecd49f50981a0fac06820ac011dc2f" +checksum = "8e03d6e8524b5093252fb624a5bb7a0517a1f23d2d2a1418ef8bfd81290ef549" dependencies = [ "anyhow", "cranelift-codegen", @@ -166,9 +167,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a42424c956bbc31fc5c2706073df896156c5420ae8fa2a5d48dbc7b295d71b" +checksum = "2a3f84c75e578189ff7a716c24ad83740b553bf583f2510b323bfe4c1a74bb93" dependencies = [ "cranelift-codegen", "libc", @@ -177,9 +178,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.111.0" +version = "0.112.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf5e2484ab47fe38a3150747cdd2016535f13542a925acca152b63383a6591b" +checksum = "bc18e6930ac086d1fe10da77d7019f29048feb7b73b236bddf8980b587ed89d7" dependencies = [ "anyhow", "cranelift-codegen", @@ -222,15 +223,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -247,7 +239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -294,7 +286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "crc32fast", - "hashbrown 0.14.5", + "hashbrown", "indexmap", "memchr", ] @@ -314,6 +306,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulley-interpreter" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70269a5a7464ccb9ab906534d44dfbd2e2f547d9fe74c08a528548d029ec641d" +dependencies = [ + "cranelift-bitset", + "log", + "sptr", +] + [[package]] name = "quote" version = "1.0.36" @@ -325,11 +328,11 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0" dependencies = [ - "hashbrown 0.13.2", + "hashbrown", "log", "rustc-hash", "slice-group-by", @@ -350,9 +353,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc_codegen_cranelift" @@ -384,6 +387,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -421,9 +430,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "24.0.0" +version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15de8429db996f0d17a4163a35eccc3f874cbfb50f29c379951ea1bbb39452e" +checksum = "48011232c0da424f89c3752a378d0b7f512fae321ea414a43e1e7a302a6a1f7e" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 6594ffb5d66bd..255f04d084d9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.111.0", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.111.0" } -cranelift-module = { version = "0.111.0" } -cranelift-native = { version = "0.111.0" } -cranelift-jit = { version = "0.111.0", optional = true } -cranelift-object = { version = "0.111.0" } +cranelift-codegen = { version = "0.112.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.112.0" } +cranelift-module = { version = "0.112.0" } +cranelift-native = { version = "0.112.0" } +cranelift-jit = { version = "0.112.0", optional = true } +cranelift-object = { version = "0.112.0" } target-lexicon = "0.12.0" gimli = { version = "0.29", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } From 9a48c44a272c46546ffce0ac50286ae9ea8c9469 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:39:04 +0000 Subject: [PATCH 0025/1110] Remove pulley-interpreter dependency --- Cargo.lock | 18 ------------------ Cargo.toml | 3 ++- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4b9d958b3577..82640dafa6d23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,6 @@ dependencies = [ "gimli", "hashbrown", "log", - "pulley-interpreter", "regalloc2", "rustc-hash", "smallvec", @@ -306,17 +305,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pulley-interpreter" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70269a5a7464ccb9ab906534d44dfbd2e2f547d9fe74c08a528548d029ec641d" -dependencies = [ - "cranelift-bitset", - "log", - "sptr", -] - [[package]] name = "quote" version = "1.0.36" @@ -387,12 +375,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "sptr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" - [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index 255f04d084d9c..a30ed75c02646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,8 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.112.0", default-features = false, features = ["std", "unwind", "all-arch"] } +# FIXME switch to native-arch instead of listing all archs on the next Cranelift update +cranelift-codegen = { version = "0.112.0", default-features = false, features = ["std", "unwind", "x86", "arm64", "s390x", "riscv64"] } cranelift-frontend = { version = "0.112.0" } cranelift-module = { version = "0.112.0" } cranelift-native = { version = "0.112.0" } From 0a9ce96e7a1d93b0b01aef48ab8ab07f2420ff60 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:13:20 +0000 Subject: [PATCH 0026/1110] Validate dir checksum during testing too Fixes rust-lang/rustc_codegen_cranelift#1394 --- build_system/prepare.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 30bd7ae26a186..ff1577116958e 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -89,6 +89,19 @@ impl GitRepo { } } + fn verify_checksum(&self, dirs: &Dirs) { + let download_dir = self.download_dir(dirs); + let actual_hash = format!("{:016x}", hash_dir(&download_dir)); + if actual_hash != self.content_hash { + eprintln!( + "Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Please run ./y.sh prepare again.", + download_dir = download_dir.display(), + content_hash = self.content_hash, + ); + std::process::exit(1); + } + } + pub(crate) fn fetch(&self, dirs: &Dirs) { let download_dir = self.download_dir(dirs); @@ -126,18 +139,11 @@ impl GitRepo { assert!(target_lockfile.exists()); } - let actual_hash = format!("{:016x}", hash_dir(&download_dir)); - if actual_hash != self.content_hash { - eprintln!( - "Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}", - download_dir = download_dir.display(), - content_hash = self.content_hash, - ); - std::process::exit(1); - } + self.verify_checksum(dirs); } pub(crate) fn patch(&self, dirs: &Dirs) { + self.verify_checksum(dirs); apply_patches( dirs, self.patch_name, From 0f1284cea736c11d9df3e952947a3d4d5a6a00ff Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:15:15 +0000 Subject: [PATCH 0027/1110] Fix ./y.sh prepare when the download dir is clobbered --- build_system/prepare.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build_system/prepare.rs b/build_system/prepare.rs index ff1577116958e..c6f979f02786f 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -1,8 +1,8 @@ use std::ffi::OsStr; -use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::{fs, io}; use crate::path::{Dirs, RelPath}; use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait}; @@ -155,6 +155,13 @@ impl GitRepo { fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { eprintln!("[CLONE] {}", repo); + + match fs::remove_dir_all(download_dir) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = download_dir.display()), + } + // Ignore exit code as the repo may already have been checked out git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap(); From 0ba084514ad1229ccba0d4cd45c4b55f8de3d092 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:36:16 +0000 Subject: [PATCH 0028/1110] Also enable Cranelift optimizations with -Copt-level=1/2 --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f6b7981395a5f..1cc2eebc47c9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,8 +298,11 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { flags_builder.set("opt_level", "none").unwrap(); } - OptLevel::Less | OptLevel::Default => {} - OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => { + OptLevel::Less + | OptLevel::Default + | OptLevel::Size + | OptLevel::SizeMin + | OptLevel::Aggressive => { flags_builder.set("opt_level", "speed_and_size").unwrap(); } } From a146874989856a377d3bf121e3f6390f1f1bed25 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:13:40 +0200 Subject: [PATCH 0029/1110] Couple of clif ir printing improvements around abi handling --- src/abi/mod.rs | 5 +++++ src/base.rs | 6 +++--- src/pretty_clif.rs | 13 +++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 892ec3e95855e..c0aa63eab7842 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -562,6 +562,11 @@ pub(crate) fn codegen_terminator_call<'tcx>( adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); } + if fx.clif_comments.enabled() { + let nop_inst = fx.bcx.ins().nop(); + with_no_trimmed_paths!(fx.add_comment(nop_inst, format!("abi: {:?}", fn_abi))); + } + match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { diff --git a/src/base.rs b/src/base.rs index 1ce0aacab4998..b95cd7ddd0ddd 100644 --- a/src/base.rs +++ b/src/base.rs @@ -101,12 +101,12 @@ pub(crate) fn codegen_fn<'tcx>( let block_map: IndexVec = (0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect(); + let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); + // Make FunctionCx let target_config = module.target_config(); let pointer_type = target_config.pointer_type(); - let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance); - - let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); + let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance, fn_abi); let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span)) diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 13877b3b1e9ae..282763279dd8a 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -62,9 +62,9 @@ use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::ir::Fact; use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::write::{FuncWriter, PlainWriter}; -use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_target::abi::call::FnAbi; use crate::prelude::*; @@ -76,17 +76,18 @@ pub(crate) struct CommentWriter { } impl CommentWriter { - pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { + pub(crate) fn new<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, + ) -> Self { let enabled = should_write_ir(tcx); let global_comments = if enabled { with_no_trimmed_paths!({ vec![ format!("symbol {}", tcx.symbol_name(instance).name), format!("instance {:?}", instance), - format!( - "abi {:?}", - RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()) - ), + format!("abi {:?}", fn_abi), String::new(), ] }) From 0f72faa2b84dda5a1d67d2a55126572867ca5b0d Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 3 Oct 2024 23:40:21 +0100 Subject: [PATCH 0030/1110] Generate correct symbols.o for sparc-unknown-none-elf Fixes #130172 --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8857fda1e9728..77a84cfc7b759 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -209,7 +209,15 @@ pub(crate) fn create_object_file(sess: &Session) -> Option (Architecture::PowerPc64, None), "riscv32" => (Architecture::Riscv32, None), "riscv64" => (Architecture::Riscv64, None), - "sparc" => (Architecture::Sparc32Plus, None), + "sparc" => { + if sess.target.options.cpu == "v9" { + // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode + (Architecture::Sparc32Plus, None) + } else { + // Target uses V7 or V8, aka EM_SPARC + (Architecture::Sparc, None) + } + } "sparc64" => (Architecture::Sparc64, None), "avr" => (Architecture::Avr, None), "msp430" => (Architecture::Msp430, None), From 0bd0b997299a919a00442f2f8c5a244b7b847d58 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 3 Oct 2024 15:05:23 +0200 Subject: [PATCH 0031/1110] Use wide pointers consistenly across the compiler --- example/std_example.rs | 4 ++-- src/base.rs | 10 +++++----- src/common.rs | 2 +- src/debuginfo/types.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/std_example.rs b/example/std_example.rs index ebaa9c69c810a..3078288c28615 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -168,7 +168,7 @@ fn main() { foo(I64X2([0, 0])); - transmute_fat_pointer(); + transmute_wide_pointer(); rust_call_abi(); @@ -192,7 +192,7 @@ type TwoPtrs = i64; #[cfg(target_pointer_width = "64")] type TwoPtrs = i128; -fn transmute_fat_pointer() -> TwoPtrs { +fn transmute_wide_pointer() -> TwoPtrs { unsafe { transmute::<_, TwoPtrs>("true !") } } diff --git a/src/base.rs b/src/base.rs index 1ce0aacab4998..0968062206940 100644 --- a/src/base.rs +++ b/src/base.rs @@ -713,17 +713,17 @@ fn codegen_stmt<'tcx>( let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); - fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { + fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { ty.builtin_deref(true) .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) } - if is_fat_ptr(fx, from_ty) { - if is_fat_ptr(fx, to_ty) { - // fat-ptr -> fat-ptr + if is_wide_ptr(fx, from_ty) { + if is_wide_ptr(fx, to_ty) { + // wide-ptr -> wide-ptr lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout)); } else { - // fat-ptr -> thin-ptr + // wide-ptr -> thin-ptr let (ptr, _extra) = operand.load_scalar_pair(fx); lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout)) } diff --git a/src/common.rs b/src/common.rs index e78ba5a341531..69a32cc3d43c9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>( }) } -/// Is a pointer to this type a fat ptr? +/// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { if ty.is_sized(tcx, ParamEnv::reveal_all()) { return false; diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index a710701e72c4b..714742aeaffe0 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -139,7 +139,7 @@ impl DebugContext { pointer_type_id } else { - // FIXME implement debuginfo for fat pointers + // FIXME implement debuginfo for wide pointers self.placeholder_for_type(tcx, type_dbg, ptr_type) } } From 6828a1edc63819120c7d11544f149cdd839ef915 Mon Sep 17 00:00:00 2001 From: ltdk Date: Fri, 4 Oct 2024 13:03:43 -0400 Subject: [PATCH 0032/1110] Stabilize UnsafeCell::from_mut --- library/core/src/cell.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index de212581e825e..26be316a7b9e2 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2115,7 +2115,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// # #![feature(unsafe_cell_from_mut)] /// use std::cell::UnsafeCell; /// /// let mut val = 42; @@ -2125,7 +2124,9 @@ impl UnsafeCell { /// assert_eq!(*uc.get_mut(), 41); /// ``` #[inline(always)] - #[unstable(feature = "unsafe_cell_from_mut", issue = "111645")] + #[stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn from_mut(value: &mut T) -> &mut UnsafeCell { // SAFETY: `UnsafeCell` has the same memory layout as `T` due to #[repr(transparent)]. unsafe { &mut *(value as *mut T as *mut UnsafeCell) } From 2811ce715dee288f83a56bbb96aac8955efbcd93 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 5 Sep 2024 19:45:40 +0200 Subject: [PATCH 0033/1110] various fixes for `naked_asm!` implementation - fix for divergence - fix error message - fix another cranelift test - fix some cranelift things - don't set the NORETURN option for naked asm - fix use of naked_asm! in doc comment - fix use of naked_asm! in run-make test - use `span_bug` in unreachable branch --- example/mini_core.rs | 6 ++++++ example/mini_core_hello_world.rs | 2 +- src/base.rs | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 5e535ff62e173..9fc0318df5dc0 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -726,6 +726,12 @@ pub macro global_asm() { /* compiler built-in */ } +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro naked_asm() { + /* compiler built-in */ +} + pub static A_STATIC: u8 = 42; #[lang = "panic_location"] diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index ccbd5a78485d7..e47431e0f873a 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -390,7 +390,7 @@ global_asm! { #[naked] extern "C" fn naked_test() { unsafe { - asm!("ret", options(noreturn)); + naked_asm!("ret"); } } diff --git a/src/base.rs b/src/base.rs index 0968062206940..a681e6d9f3cd1 100644 --- a/src/base.rs +++ b/src/base.rs @@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; @@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>( match &mir.basic_blocks[START_BLOCK].terminator().kind { TerminatorKind::InlineAsm { + asm_macro: InlineAsmMacro::NakedAsm, template, operands, options, @@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { "tail calls are not yet supported in `rustc_codegen_cranelift` backend" ), TerminatorKind::InlineAsm { + asm_macro: _, template, operands, options, From fead1d5634f8badb0dd8436032334916bfdff7e4 Mon Sep 17 00:00:00 2001 From: rickdewater Date: Mon, 7 Oct 2024 22:35:54 +0200 Subject: [PATCH 0034/1110] Add LowerExp and UpperExp implementations Mark the new fmt impls with the correct rust version Clean up the fmt macro and format the tests --- library/core/src/num/nonzero.rs | 46 +++++++++++++++++++++------------ library/core/tests/nonzero.rs | 11 ++++++++ 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e5c9a7e086ac9..512c7ffa30509 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -110,26 +110,40 @@ impl_zeroable_primitive!( pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { - ($Trait:ident) => { - #[stable(feature = "nonzero", since = "1.28.0")] - impl fmt::$Trait for NonZero - where - T: ZeroablePrimitive + fmt::$Trait, - { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) + ($(#[$Attribute:meta] $Trait:ident)*) => { + $( + #[$Attribute] + impl fmt::$Trait for NonZero + where + T: ZeroablePrimitive + fmt::$Trait, + { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } } - } + )* }; } -impl_nonzero_fmt!(Debug); -impl_nonzero_fmt!(Display); -impl_nonzero_fmt!(Binary); -impl_nonzero_fmt!(Octal); -impl_nonzero_fmt!(LowerHex); -impl_nonzero_fmt!(UpperHex); +impl_nonzero_fmt! { + #[stable(feature = "nonzero", since = "1.28.0")] + Debug + #[stable(feature = "nonzero", since = "1.28.0")] + Display + #[stable(feature = "nonzero", since = "1.28.0")] + Binary + #[stable(feature = "nonzero", since = "1.28.0")] + Octal + #[stable(feature = "nonzero", since = "1.28.0")] + LowerHex + #[stable(feature = "nonzero", since = "1.28.0")] + UpperHex + #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + LowerExp + #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + UpperExp +} macro_rules! impl_nonzero_auto_trait { (unsafe $Trait:ident) => { diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index d728513a4e297..43c279053d829 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -354,3 +354,14 @@ fn test_signed_nonzero_neg() { assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); } + +#[test] +fn test_nonzero_fmt() { + let i = format!("{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", 42); + let nz = format!( + "{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", + NonZero::new(42).unwrap() + ); + + assert_eq!(i, nz); +} From b95aa31a75fd181ff1f84e1bb0a160854d8d383f Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Tue, 8 Oct 2024 00:13:59 -0400 Subject: [PATCH 0035/1110] Stabilize `isqrt` feature --- tests/ui/cast.rs | 1 - tests/ui/cast.stderr | 184 +++++++++++++++++++++---------------------- 2 files changed, 92 insertions(+), 93 deletions(-) diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 146b04ab8131d..0de53a75c6236 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,7 +1,6 @@ //@no-rustfix #![feature(repr128)] -#![feature(isqrt)] #![allow(incomplete_features)] #![warn( clippy::cast_precision_loss, diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 7824bdfac25ef..452482fc88e28 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:25:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:30:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:31:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:35:5 + --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:38:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:39:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:43:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:49:5 + --> tests/ui/cast.rs:48:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:52:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:55:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:65:22 + --> tests/ui/cast.rs:64:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:66:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:69:9 + --> tests/ui/cast.rs:68:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:75:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:78:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:81:5 + --> tests/ui/cast.rs:80:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:83:5 + --> tests/ui/cast.rs:82:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:85:5 + --> tests/ui/cast.rs:84:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:100:5 + --> tests/ui/cast.rs:99:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:105:5 + --> tests/ui/cast.rs:104:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:108:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:117:5 + --> tests/ui/cast.rs:116:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:120:5 + --> tests/ui/cast.rs:119:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:131:5 + --> tests/ui/cast.rs:130:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:134:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:136:5 + --> tests/ui/cast.rs:135:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:143:5 + --> tests/ui/cast.rs:142:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:158:5 + --> tests/ui/cast.rs:157:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:209:5 + --> tests/ui/cast.rs:208:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:223:5 + --> tests/ui/cast.rs:222:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:246:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:248:21 + --> tests/ui/cast.rs:247:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:290:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:292:21 + --> tests/ui/cast.rs:291:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:309:21 + --> tests/ui/cast.rs:308:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:328:21 + --> tests/ui/cast.rs:327:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:375:21 + --> tests/ui/cast.rs:374:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:386:13 + --> tests/ui/cast.rs:385:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:390:13 + --> tests/ui/cast.rs:389:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:402:9 + --> tests/ui/cast.rs:401:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:407:32 + --> tests/ui/cast.rs:406:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:409:5 + --> tests/ui/cast.rs:408:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:410:5 + --> tests/ui/cast.rs:409:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:415:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:417:5 + --> tests/ui/cast.rs:416:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:419:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:423:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:429:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:430:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:432:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:433:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:434:6 + --> tests/ui/cast.rs:433:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:437:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:439:5 + --> tests/ui/cast.rs:438:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:443:5 + --> tests/ui/cast.rs:442:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:445:5 + --> tests/ui/cast.rs:444:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:447:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:448:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:9 + --> tests/ui/cast.rs:450:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:452:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:453:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:455:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:461:9 + --> tests/ui/cast.rs:460:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:463:9 + --> tests/ui/cast.rs:462:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:465:9 + --> tests/ui/cast.rs:464:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:475:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:499:5 + --> tests/ui/cast.rs:498:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:501:5 + --> tests/ui/cast.rs:500:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ From 48504415cff11ac421bce701be4c0188afed77ef Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 8 Oct 2024 17:26:42 -0700 Subject: [PATCH 0036/1110] cg_clif: Factor out rustc_target::abi --- src/discriminant.rs | 3 ++- src/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/discriminant.rs b/src/discriminant.rs index e7ac084558a5a..d462dcd63a925 100644 --- a/src/discriminant.rs +++ b/src/discriminant.rs @@ -3,7 +3,8 @@ //! Adapted from //! () -use rustc_target::abi::{Int, TagEncoding, Variants}; +use rustc_abi::Primitive::Int; +use rustc_abi::{TagEncoding, Variants}; use crate::prelude::*; diff --git a/src/lib.rs b/src/lib.rs index f6b7981395a5f..b6f9ce8fc2988 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ extern crate jobserver; #[macro_use] extern crate rustc_middle; +extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; From 14f656ede3d56eb786efd785137406111d028a09 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:09:42 +0000 Subject: [PATCH 0037/1110] Compile all abi-cafe tests with debuginfo enabled --- patches/0002-abi-cafe-Disable-broken-tests.patch | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/patches/0002-abi-cafe-Disable-broken-tests.patch b/patches/0002-abi-cafe-Disable-broken-tests.patch index 8a2565f1668ad..4c89d65234a4a 100644 --- a/patches/0002-abi-cafe-Disable-broken-tests.patch +++ b/patches/0002-abi-cafe-Disable-broken-tests.patch @@ -7,6 +7,18 @@ Subject: [PATCH] Disable broken tests src/report.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) +diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs +index 0c50f7a..bfde2b1 100644 +--- a/src/toolchains/rust.rs ++++ b/src/toolchains/rust.rs +@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { + .arg(out_dir) + .arg("--target") + .arg(built_info::TARGET) ++ .arg("-g") + .arg(format!("-Cmetadata={lib_name}")) + .arg(src_path); + if let Some(codegen_backend) = &self.codegen_backend { diff --git a/src/report.rs b/src/report.rs index 958ab43..dcf1044 100644 --- a/src/report.rs From 5d7d2518b38721251eee477f62078ea70c303d69 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:19:54 +0000 Subject: [PATCH 0038/1110] Rustup to rustc 1.83.0-nightly (eb4e23467 2024-10-09) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 093f5bdc4dae0..775402b2b5eba 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-09-26" +channel = "nightly-2024-10-10" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 76dfce7a6f8aaf421d32027f96ffb030a979bd79 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:32:42 +0000 Subject: [PATCH 0039/1110] Fix rustc test suite --- scripts/test_rustc_tests.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 7c38792a6034f..fbf4ce0223416 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -47,9 +47,6 @@ rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support rm tests/ui/delegation/fn-header.rs -# unsized locals -rm -r tests/run-pass-valgrind/unsized-locals - # misc unimplemented things rm tests/ui/target-feature/missing-plusminus.rs # error not implemented rm -r tests/run-make/repr128-dwarf # debuginfo test @@ -183,5 +180,5 @@ index 9607ff02f96..b7d97caf9a2 100644 EOF echo "[TEST] rustc test suite" -COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental} +COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental} popd From cbe428d8cb60f901cae2c99a5aff0f563b142681 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Thu, 18 Aug 2022 20:23:01 -0700 Subject: [PATCH 0040/1110] use `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)` as a `TMPDIR` fallback on darwin --- library/std/src/env.rs | 15 ++++- library/std/src/sys/pal/unix/os.rs | 76 ++++++++++++++++++++++-- library/std/src/sys/pal/unix/os/tests.rs | 25 ++++++++ 3 files changed, 109 insertions(+), 7 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 97a1b846a91a4..5a2deada6c355 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -653,19 +653,28 @@ pub fn home_dir() -> Option { /// may result in "insecure temporary file" security vulnerabilities. Consider /// using a crate that securely creates temporary files or directories. /// +/// Note that the returned value may be a symbolic link, not a directory. +/// /// # Platform-specific behavior /// /// On Unix, returns the value of the `TMPDIR` environment variable if it is -/// set, otherwise for non-Android it returns `/tmp`. On Android, since there -/// is no global temporary folder (it is usually allocated per-app), it returns -/// `/data/local/tmp`. +/// set, otherwise the value is OS-specific: +/// - On Android, there is no global temporary folder (it is usually allocated +/// per-app), it returns `/data/local/tmp`. +/// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided +/// by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's +/// security guidelines][appledoc]. +/// - On all other unix-based OSes, it returns `/tmp`. +/// /// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] / /// [`GetTempPath`][GetTempPath], which this function uses internally. +/// /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior /// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a /// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha +/// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 /// /// ```no_run /// use std::env; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f983d174ed61c..7db037d02eba0 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -698,12 +698,80 @@ pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } } +// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only +// used on Darwin, but should work on any unix (in case we need to get +// `_CS_PATH` or `_CS_V[67]_ENV` in the future). +// +// [posix_confstr]: +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +fn confstr(key: c_int, size_hint: Option) -> io::Result { + let mut buf: Vec = Vec::new(); + let mut bytes_needed_including_nul = size_hint + .unwrap_or_else(|| { + // Treat "None" as "do an extra call to get the length". In theory + // we could move this into the loop below, but it's hard to do given + // that it isn't 100% clear if it's legal to pass 0 for `len` when + // the buffer isn't null. + unsafe { libc::confstr(key, core::ptr::null_mut(), 0) } + }) + .max(1); + // If the value returned by `confstr` is greater than the len passed into + // it, then the value was truncated, meaning we need to retry. Note that + // while `confstr` results don't seem to change for a process, it's unclear + // if this is guaranteed anywhere, so looping does seem required. + while bytes_needed_including_nul > buf.capacity() { + // We write into the spare capacity of `buf`. This lets us avoid + // changing buf's `len`, which both simplifies `reserve` computation, + // allows working with `Vec` instead of `Vec>`, and + // may avoid a copy, since the Vec knows that none of the bytes are needed + // when reallocating (well, in theory anyway). + buf.reserve(bytes_needed_including_nul); + // `confstr` returns + // - 0 in the case of errors: we break and return an error. + // - The number of bytes written, iff the provided buffer is enough to + // hold the entire value: we break and return the data in `buf`. + // - Otherwise, the number of bytes needed (including nul): we go + // through the loop again. + bytes_needed_including_nul = + unsafe { libc::confstr(key, buf.as_mut_ptr().cast::(), buf.capacity()) }; + } + // `confstr` returns 0 in the case of an error. + if bytes_needed_including_nul == 0 { + return Err(io::Error::last_os_error()); + } + // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a + // non-zero value, meaning `bytes_needed_including_nul` bytes were + // initialized. + unsafe { + buf.set_len(bytes_needed_including_nul); + // Remove the NUL-terminator. + let last_byte = buf.pop(); + // ... and smoke-check that it *was* a NUL-terminator. + assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated"); + }; + Ok(OsString::from_vec(buf)) +} + +#[cfg(target_vendor = "apple")] +fn darwin_temp_dir() -> PathBuf { + confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| { + // It failed for whatever reason (there are several possible reasons), + // so return the global one. + PathBuf::from("/tmp") + }) +} + pub fn temp_dir() -> PathBuf { crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { - if cfg!(target_os = "android") { - PathBuf::from("/data/local/tmp") - } else { - PathBuf::from("/tmp") + cfg_if::cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { + darwin_temp_dir() + } else if #[cfg(target_os = "android")] { + PathBuf::from("/data/local/tmp") + } else { + PathBuf::from("/tmp") + } } }) } diff --git a/library/std/src/sys/pal/unix/os/tests.rs b/library/std/src/sys/pal/unix/os/tests.rs index efc29955b05fe..ab9742fc677e9 100644 --- a/library/std/src/sys/pal/unix/os/tests.rs +++ b/library/std/src/sys/pal/unix/os/tests.rs @@ -21,3 +21,28 @@ fn test_parse_glibc_version() { assert_eq!(parsed, super::parse_glibc_version(version_str)); } } + +// Smoke check `confstr`, do it for several hint values, to ensure our resizing +// logic is correct. +#[test] +#[cfg(target_os = "macos")] +fn test_confstr() { + for key in [libc::_CS_DARWIN_USER_TEMP_DIR, libc::_CS_PATH] { + let value_nohint = super::confstr(key, None).unwrap_or_else(|e| { + panic!("confstr({key}, None) failed: {e:?}"); + }); + let end = (value_nohint.len() + 1) * 2; + for hint in 0..end { + assert_eq!( + super::confstr(key, Some(hint)).as_deref().ok(), + Some(&*value_nohint), + "confstr({key}, Some({hint})) failed", + ); + } + } + // Smoke check that we don't loop forever or something if the input was not valid. + for hint in [None, Some(0), Some(1)] { + let hopefully_invalid = 123456789_i32; + assert!(super::confstr(hopefully_invalid, hint).is_err()); + } +} From 6d075dc4d7335a239f887b28a630bdc9aa08e140 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 10 Oct 2024 18:41:55 +0200 Subject: [PATCH 0041/1110] Prefer `target_vendor = "apple"` on confstr --- library/std/src/sys/pal/unix/os.rs | 4 ++-- library/std/src/sys/pal/unix/os/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 7db037d02eba0..9750c32eed5e5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -704,7 +704,7 @@ pub fn page_size() -> usize { // // [posix_confstr]: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(target_vendor = "apple")] fn confstr(key: c_int, size_hint: Option) -> io::Result { let mut buf: Vec = Vec::new(); let mut bytes_needed_including_nul = size_hint @@ -765,7 +765,7 @@ fn darwin_temp_dir() -> PathBuf { pub fn temp_dir() -> PathBuf { crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { cfg_if::cfg_if! { - if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { + if #[cfg(target_vendor = "apple")] { darwin_temp_dir() } else if #[cfg(target_os = "android")] { PathBuf::from("/data/local/tmp") diff --git a/library/std/src/sys/pal/unix/os/tests.rs b/library/std/src/sys/pal/unix/os/tests.rs index ab9742fc677e9..a84086037ce0b 100644 --- a/library/std/src/sys/pal/unix/os/tests.rs +++ b/library/std/src/sys/pal/unix/os/tests.rs @@ -25,7 +25,7 @@ fn test_parse_glibc_version() { // Smoke check `confstr`, do it for several hint values, to ensure our resizing // logic is correct. #[test] -#[cfg(target_os = "macos")] +#[cfg(target_vendor = "apple")] fn test_confstr() { for key in [libc::_CS_DARWIN_USER_TEMP_DIR, libc::_CS_PATH] { let value_nohint = super::confstr(key, None).unwrap_or_else(|e| { From b62ee10e5448a077e67e46f6907a4a04415895a8 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 10 Oct 2024 18:57:44 +0200 Subject: [PATCH 0042/1110] Use with_capacity(0) because we're reading the capacity later on --- library/std/src/sys/pal/unix/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 9750c32eed5e5..d26a1bdef74b4 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -706,7 +706,7 @@ pub fn page_size() -> usize { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html #[cfg(target_vendor = "apple")] fn confstr(key: c_int, size_hint: Option) -> io::Result { - let mut buf: Vec = Vec::new(); + let mut buf: Vec = Vec::with_capacity(0); let mut bytes_needed_including_nul = size_hint .unwrap_or_else(|| { // Treat "None" as "do an extra call to get the length". In theory From 3727a8c4d8169043a40f327dbd39db0c4448aef6 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 1 Sep 2024 04:20:20 +0530 Subject: [PATCH 0043/1110] uefi: process: Add args support - Wrap all args with quotes. - Escape ^ and " inside quotes using ^. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 68 ++++++++++++++++++++----- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index fdc5f5d7e4fea..4494b3df57bdd 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -18,6 +18,7 @@ use crate::{fmt, io}; #[derive(Debug)] pub struct Command { prog: OsString, + args: Vec, stdout: Option, stderr: Option, } @@ -39,12 +40,11 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } - // FIXME: Implement arguments as reverse of parsing algorithm - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -72,7 +72,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -116,6 +116,12 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + // UEFI adds the bin name by default + if !self.args.is_empty() { + let args = uefi_command_internal::create_args(&self.prog, &self.args); + cmd.set_args(args); + } + // Setup Stdout let stdout = self.stdout.unwrap_or(Stdio::MakePipe); let stdout = Self::create_pipe(stdout)?; @@ -315,7 +321,7 @@ mod uefi_command_internal { stdout: Option>, stderr: Option>, st: OwnedTable, - args: Option>, + args: Option<(*mut u16, usize)>, } impl Image { @@ -449,20 +455,20 @@ mod uefi_command_internal { } } - pub fn set_args(&mut self, args: &OsStr) { + pub fn set_args(&mut self, args: Box<[u16]>) { let loaded_image: NonNull = helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut args = args.encode_wide().collect::>(); - let args_size = (crate::mem::size_of::() * args.len()) as u32; + let len = args.len(); + let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { - (*loaded_image.as_ptr()).load_options = - args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void; (*loaded_image.as_ptr()).load_options_size = args_size; } - self.args = Some(args); + self.args = Some((ptr, len)); } fn update_st_crc32(&mut self) -> io::Result<()> { @@ -502,6 +508,10 @@ mod uefi_command_internal { ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); } } + + if let Some((ptr, len)) = self.args { + let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + } } } @@ -681,4 +691,38 @@ mod uefi_command_internal { } } } + + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + const QUOTE: u16 = 0x0022; + const SPACE: u16 = 0x0020; + const CARET: u16 = 0x005e; + const NULL: u16 = 0; + + // This is the lower bound on the final length under the assumption that + // the arguments only contain ASCII characters. + let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); + + // Wrap program name in quotes to avoid any problems + res.push(QUOTE); + res.extend(prog.encode_wide()); + res.push(QUOTE); + res.push(SPACE); + + for arg in args { + // Wrap the argument in quotes to be treat as single arg + res.push(QUOTE); + for c in arg.encode_wide() { + // CARET in quotes is used to escape CARET or QUOTE + if c == QUOTE || c == CARET { + res.push(CARET); + } + res.push(c); + } + res.push(QUOTE); + + res.push(SPACE); + } + + res.into_boxed_slice() + } } From 809dc73d90d191c75b24840113797bd4f7e138b3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 11 Oct 2024 11:54:16 +0100 Subject: [PATCH 0044/1110] Make asm label blocks safe context `asm!()` is forced to be wrapped inside unsafe. If there's no special treatment, the label blocks would also always be unsafe with no way of opting out. --- .../rustc_mir_build/src/check_unsafety.rs | 39 ++++++++++++++++++- .../src/language-features/asm-goto.md | 4 +- tests/ui/asm/x86_64/goto-block-safe.rs | 23 +++++++++++ tests/ui/asm/x86_64/goto-block-safe.stderr | 14 +++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/ui/asm/x86_64/goto-block-safe.rs create mode 100644 tests/ui/asm/x86_64/goto-block-safe.stderr diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8512763a595d5..2e3169bbf89b1 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -541,8 +541,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(expr.span, DerefOfRawPointer); } } - ExprKind::InlineAsm { .. } => { + ExprKind::InlineAsm(box InlineAsmExpr { + asm_macro: _, + ref operands, + template: _, + options: _, + line_spans: _, + }) => { self.requires_unsafe(expr.span, UseOfInlineAssembly); + + // For inline asm, do not use `walk_expr`, since we want to handle the label block + // specially. + for op in &**operands { + use rustc_middle::thir::InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + self.visit_expr(&self.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + self.visit_expr(&self.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymFn { value: _, span: _ } + | SymStatic { def_id: _ } => {} + Label { block } => { + // Label blocks are safe context. + // `asm!()` is forced to be wrapped inside unsafe. If there's no special + // treatment, the label blocks would also always be unsafe with no way + // of opting out. + self.in_safety_context(SafetyContext::Safe, |this| { + visit::walk_block(this, &this.thir()[*block]) + }); + } + } + } + return; } ExprKind::Adt(box AdtExpr { adt_def, diff --git a/src/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md index d72eb7c0c6ef1..823118bcae1e1 100644 --- a/src/doc/unstable-book/src/language-features/asm-goto.md +++ b/src/doc/unstable-book/src/language-features/asm-goto.md @@ -21,7 +21,9 @@ unsafe { } ``` -The block must have unit type or diverge. +The block must have unit type or diverge. The block starts a new safety context, +so despite outer `unsafe`, you need extra unsafe to perform unsafe operations +within `label `. When `label ` is used together with `noreturn` option, it means that the assembly will not fallthrough. It's allowed to jump to a label within the diff --git a/tests/ui/asm/x86_64/goto-block-safe.rs b/tests/ui/asm/x86_64/goto-block-safe.rs new file mode 100644 index 0000000000000..ee833a48a4b19 --- /dev/null +++ b/tests/ui/asm/x86_64/goto-block-safe.rs @@ -0,0 +1,23 @@ +//@ only-x86_64 +//@ needs-asm-support + +#![deny(unreachable_code)] +#![feature(asm_goto)] + +use std::arch::asm; + +fn goto_fallthough() { + unsafe { + asm!( + "/* {} */", + label { + core::hint::unreachable_unchecked(); + //~^ ERROR [E0133] + } + ) + } +} + +fn main() { + goto_fallthough(); +} diff --git a/tests/ui/asm/x86_64/goto-block-safe.stderr b/tests/ui/asm/x86_64/goto-block-safe.stderr new file mode 100644 index 0000000000000..49818db7484e5 --- /dev/null +++ b/tests/ui/asm/x86_64/goto-block-safe.stderr @@ -0,0 +1,14 @@ +error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block + --> $DIR/goto-block-safe.rs:14:17 + | +LL | unsafe { + | ------ items do not inherit unsafety from separate enclosing items +... +LL | core::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. From 270fb2130c979fe1d1e520dbb8474aa13257d16b Mon Sep 17 00:00:00 2001 From: Jed Brown Date: Fri, 5 Jan 2024 21:04:41 -0700 Subject: [PATCH 0045/1110] intrinsics.fmuladdf{16,32,64,128}: expose llvm.fmuladd.* semantics Add intrinsics `fmuladd{f16,f32,f64,f128}`. This computes `(a * b) + c`, to be fused if the code generator determines that (i) the target instruction set has support for a fused operation, and (ii) that the fused operation is more efficient than the equivalent, separate pair of `mul` and `add` instructions. https://llvm.org/docs/LangRef.html#llvm-fmuladd-intrinsic MIRI support is included for f32 and f64. The codegen_cranelift uses the `fma` function from libc, which is a correct implementation, but without the desired performance semantic. I think this requires an update to cranelift to expose a suitable instruction in its IR. I have not tested with codegen_gcc, but it should behave the same way (using `fma` from libc). --- src/intrinsics/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 19e5adc253854..35f0ccff3f99e 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -328,6 +328,9 @@ fn codegen_float_intrinsic_call<'tcx>( sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), + // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation + sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f32 + sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f64 sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32), @@ -381,7 +384,7 @@ fn codegen_float_intrinsic_call<'tcx>( let layout = fx.layout_of(ty); let res = match intrinsic { - sym::fmaf32 | sym::fmaf64 => { + sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => { CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout) } sym::copysignf32 | sym::copysignf64 => { From 6b1779b0ee1eb2a660543c816536f66c8f822d57 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sat, 12 Oct 2024 23:32:50 +0100 Subject: [PATCH 0046/1110] Add lint to check for slow symbol comparisons --- clippy_lints/src/declared_lints.rs | 2 + clippy_lints/src/lib.rs | 1 + clippy_lints/src/utils/internal_lints.rs | 1 + .../internal_lints/slow_symbol_comparisons.rs | 69 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0f9dbec8a755b..f75be5fc48f44 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -28,6 +28,8 @@ pub static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] + crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO, + #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b2229b53afd23..a817f63790441 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -605,6 +605,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| { Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new()) }); + store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons)); } store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index f662c7651f6bb..deb983b6971dc 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -6,5 +6,6 @@ pub mod lint_without_lint_pass; pub mod msrv_attr_impl; pub mod outer_expn_data_pass; pub mod produce_ice; +pub mod slow_symbol_comparisons; pub mod unnecessary_def_path; pub mod unsorted_clippy_utils_paths; diff --git a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs new file mode 100644 index 0000000000000..3742be0e103d6 --- /dev/null +++ b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs @@ -0,0 +1,69 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use clippy_utils::{match_function_call, paths}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// + /// Detects symbol comparision using `Symbol::intern`. + /// + /// ### Why is this bad? + /// + /// Comparision via `Symbol::as_str()` is faster if the interned symbols are not reused. + /// + /// ### Example + /// + /// None, see suggestion. + pub SLOW_SYMBOL_COMPARISONS, + internal, + "detects slow comparisions of symbol" +} + +declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); + +fn check_slow_comparison<'tcx>( + cx: &LateContext<'tcx>, + op1: &'tcx Expr<'tcx>, + op2: &'tcx Expr<'tcx>, +) -> Option<(Span, String)> { + if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) + && let Some([symbol_name_expr]) = match_function_call(cx, op2, &paths::SYMBOL_INTERN) + && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) + { + Some((op1.span, symbol_name)) + } else { + None + } +} + +impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Binary(op, left, right) = expr.kind + && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) + && let Some((symbol_span, symbol_name)) = + check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left)) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + SLOW_SYMBOL_COMPARISONS, + expr.span, + "comparing `Symbol` via `Symbol::intern`", + "use `Symbol::as_str` and check the string instead", + format!( + "{}.as_str() {} \"{symbol_name}\"", + snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability), + op.node.as_str() + ), + applicability, + ); + }; + } +} From dedc380df91748eeed88c269682554d8a3ab44fb Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sun, 13 Oct 2024 16:27:05 +0100 Subject: [PATCH 0047/1110] Apply fixes from lint --- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 4 ++-- clippy_lints/src/infinite_iter.rs | 6 +++--- clippy_lints/src/iter_without_into_iter.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 4 ++-- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 12 ++++++------ clippy_lints/src/methods/filter_map.rs | 4 ++-- clippy_lints/src/methods/needless_collect.rs | 2 +- clippy_lints/src/methods/read_line_without_trim.rs | 4 ++-- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/minmax.rs | 4 ++-- clippy_lints/src/missing_fields_in_debug.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 4 ++-- clippy_lints/src/operators/float_cmp.rs | 2 +- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/question_mark.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 6 +++--- clippy_lints/src/strings.rs | 6 +++--- clippy_lints/src/transmute/eager_transmute.rs | 4 ++-- .../utils/internal_lints/lint_without_lint_pass.rs | 4 +--- .../src/utils/internal_lints/msrv_attr_impl.rs | 2 +- tests/ui-internal/unnecessary_symbol_str.fixed | 1 + tests/ui-internal/unnecessary_symbol_str.rs | 1 + tests/ui-internal/unnecessary_symbol_str.stderr | 10 +++++----- 27 files changed, 50 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index b11b967f8bc78..205357afd8408 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind { - if method_path.ident.name == sym!(cast) + if method_path.ident.name.as_str() == "cast" && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args // There probably is no obvious reason to do this, just to be consistent with `as` cases. diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4e4434ec7d19c..0550c22761a56 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { // match call to write_fmt && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) && let ExprKind::Call(write_recv_path, []) = write_recv.kind - && write_fun.ident.name == sym!(write_fmt) + && write_fun.ident.name.as_str() == "write_fmt" && let Some(def_id) = path_def_id(cx, write_recv_path) { // match calls to std::io::stdout() / std::io::stderr () diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index d62d008d480f7..c8828c9361576 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -41,7 +41,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name == sym!(from_raw) + && seg.ident.name.as_str() == "from_raw" && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() && let ty::RawPtr(ty, _) = arg_kind diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 4c5375730b8e3..c370f206c8f83 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -340,7 +340,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { if method.ident.name == sym::new { self.suggestions.insert(e.span, "HashMap::default()".to_string()); - } else if method.ident.name == sym!(with_capacity) { + } else if method.ident.name.as_str() == "with_capacity" { self.suggestions.insert( e.span, format!( @@ -352,7 +352,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { if method.ident.name == sym::new { self.suggestions.insert(e.span, "HashSet::default()".to_string()); - } else if method.ident.name == sym!(with_capacity) { + } else if method.ident.name.as_str() == "with_capacity" { self.suggestions.insert( e.span, format!( diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 71c317552ee1a..48874d6064b6b 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -157,7 +157,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .and(cap); } } - if method.ident.name == sym!(flat_map) && args.len() == 1 { + if method.ident.name.as_str() == "flat_map" && args.len() == 1 { if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { let body = cx.tcx.hir().body(body); return is_infinite(cx, body.value); @@ -224,7 +224,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) && args.is_empty() { + if method.ident.name.as_str() == "last" && args.is_empty() { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) @@ -234,7 +234,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if not_double_ended { return is_infinite(cx, receiver); } - } else if method.ident.name == sym!(collect) { + } else if method.ident.name.as_str() == "collect" { let ty = cx.typeck_results().expr_ty(expr); if matches!( get_type_diagnostic_name(cx, ty), diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 1e6404190d3cf..36e94593e6fc1 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -142,7 +142,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { - if item.ident.name == sym!(IntoIter) { + if item.ident.name.as_str() == "IntoIter" { Some(cx.tcx.hir().impl_item(item.id).expect_type().span) } else { None diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index c62bd65bea683..7a9c99637428a 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -68,7 +68,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Some(init) = local.init && !init.span.from_expansion() && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind - && seg.ident.name == sym!(build_hasher) + && seg.ident.name.as_str() == "build_hasher" && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id) && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id) @@ -96,7 +96,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id) && !finish_expr.span.from_expansion() && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind - && seg.ident.name == sym!(finish) + && seg.ident.name.as_str() == "finish" && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) { diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 24207705743d1..dec8c5d85dec2 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind - && path.ident.name == sym!(contains) + && path.ident.name.as_str() == "contains" && let Some(higher::Range { start: Some(start), end: Some(end), diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 564c598a334c7..051a4eceab840 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -10,7 +10,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, sym}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind && let Some(binding) = get_pat_binding(cx, recv, outer_arm) { - check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding); + check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding); } } } @@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: fn check_method_calls<'tcx>( cx: &LateContext<'tcx>, arm: &Arm<'tcx>, - method: Symbol, + method: &str, recv: &Expr<'_>, args: &[Expr<'_>], if_expr: &Expr<'_>, @@ -112,7 +112,7 @@ fn check_method_calls<'tcx>( let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let slice_like = ty.is_slice() || ty.is_array(); - let sugg = if method == sym!(is_empty) { + let sugg = if method == "is_empty" { // `s if s.is_empty()` becomes "" // `arr if arr.is_empty()` becomes [] @@ -137,9 +137,9 @@ fn check_method_calls<'tcx>( if needles.is_empty() { sugg.insert_str(1, ".."); - } else if method == sym!(starts_with) { + } else if method == "starts_with" { sugg.insert_str(sugg.len() - 1, ", .."); - } else if method == sym!(ends_with) { + } else if method == "ends_with" { sugg.insert_str(1, ".., "); } else { return; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 06482a743ddf4..c181e944fff88 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -234,12 +234,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) { + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" { Some(Self::IsSome { receiver, side_effect_expr_span, }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) { + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" { Some(Self::IsOk { receiver, side_effect_expr_span, diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 96a31812ca475..055107068ae03 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if args.is_empty() - && method_name.ident.name == sym!(collect) + && method_name.ident.name.as_str() == "collect" && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs index 65e545ed03a02..db2b9d4d92fb6 100644 --- a/clippy_lints/src/methods/read_line_without_trim.rs +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -44,7 +44,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< if let Some(parent) = get_parent_expr(cx, expr) { let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind { if args.is_empty() - && segment.ident.name == sym!(parse) + && segment.ident.name.as_str() == "parse" && let parse_result_ty = cx.typeck_results().expr_ty(parent) && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) && let ty::Adt(_, substs) = parse_result_ty.kind() @@ -58,7 +58,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< "calling `.parse()` on a string without trimming the trailing newline character", "checking", )) - } else if segment.ident.name == sym!(ends_with) + } else if segment.ident.name.as_str() == "ends_with" && recv.span == expr.span && let [arg] = args && expr_is_string_literal_without_trailing_newline(arg) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ca46da81fa053..1cbb1bcc663e2 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -78,7 +78,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc (true, true) }, hir::ExprKind::MethodCall(segment, recv, [arg], _) => { - if segment.ident.name == sym!(then_some) + if segment.ident.name.as_str() == "then_some" && cx.typeck_results().expr_ty(recv).is_bool() && path_to_local_id(arg, arg_id) { diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index e95864c6db8b5..ed89b3b34386f 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -79,9 +79,9 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { - if path.ident.name == sym!(max) { + if path.ident.name.as_str() == "max" { fetch_const(cx, Some(receiver), args, MinMax::Max) - } else if path.ident.name == sym!(min) { + } else if path.ident.name.as_str() == "min" { fetch_const(cx, Some(receiver), args, MinMax::Min) } else { None diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index fc01b6753f1c7..f28b431ab997e 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -116,7 +116,7 @@ fn should_lint<'tcx>( if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name == sym!(finish_non_exhaustive) + } else if path.ident.name.as_str() == "finish_non_exhaustive" && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) { has_finish_non_exhaustive = true; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 3f156aa551040..0caa19cd84436 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() - && ((path.ident.name == sym!(mode) + && ((path.ident.name.as_str() == "mode" && matches!( cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder) )) - || (path.ident.name == sym!(set_mode) + || (path.ident.name.as_str() == "set_mode" && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index 8e394944c2130..ab5f91c1d6725 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -107,7 +107,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind - && sym!(signum) == method_name.ident.name + && method_name.ident.name.as_str() == "signum" // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) { diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 56d07aeae1758..808a7e005c679 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -96,7 +96,7 @@ fn expr_as_ptr_offset_call<'tcx>( if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); } - if path_segment.ident.name == sym!(wrapping_offset) { + if path_segment.ident.name.as_str() == "wrapping_offset" { return Some((arg_0, arg_1, Method::WrappingOffset)); } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 9344cb41993a7..28968866e1f8e 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -163,8 +163,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ is_type_diagnostic_item(cx, caller_ty, smbl) && expr_return_none_or_err(smbl, cx, if_then, caller, None) && match smbl { - sym::Option => call_sym == sym!(is_none), - sym::Result => call_sym == sym!(is_err), + sym::Option => call_sym.as_str() == "is_none", + sym::Result => call_sym.as_str() == "is_err", _ => false, } }, diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index ec6e45256d149..8c8f11569c8c2 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -235,7 +235,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name == sym!(extend) + && path.ident.name.as_str() == "extend" && self.is_repeat_take(extend_arg) { self.slow_expression = Some(InitializationType::Extend(expr)); @@ -247,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name == sym!(resize) + && path.ident.name.as_str() == "resize" // Check that is filled with 0 && is_integer_literal(fill_arg, 0) { @@ -269,7 +269,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool { if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind - && take_path.ident.name == sym!(take) + && take_path.ident.name.as_str() == "take" // Check that take is applied to `repeat(0)` && self.is_repeat_zero(recv) { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index bf49bb6016293..e09c07060065c 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if !in_external_macro(cx.sess(), e.span) && let ExprKind::MethodCall(path, receiver, ..) = &e.kind - && path.ident.name == sym!(as_bytes) + && path.ident.name.as_str() == "as_bytes" && let ExprKind::Lit(lit) = &receiver.kind && let LitKind::Str(lit_content, _) = &lit.node { @@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if let ExprKind::MethodCall(path, recv, [], _) = &e.kind - && path.ident.name == sym!(into_bytes) + && path.ident.name.as_str() == "into_bytes" && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind && matches!(path.ident.name.as_str(), "to_owned" | "to_string") && let ExprKind::Lit(lit) = &recv.kind @@ -493,7 +493,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind - && path.ident.name == sym!(split_whitespace) + && path.ident.name.as_str() == "split_whitespace" && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind diff --git a/clippy_lints/src/transmute/eager_transmute.rs b/clippy_lints/src/transmute/eager_transmute.rs index 1dfc9f7091e8c..ca9daf2d2a037 100644 --- a/clippy_lints/src/transmute/eager_transmute.rs +++ b/clippy_lints/src/transmute/eager_transmute.rs @@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs) }, ExprKind::MethodCall(path, receiver, [arg], _) - if path.ident.name == sym!(contains) + if path.ident.name.as_str() == "contains" // ... `contains` called on some kind of range && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def() && let lang_items = cx.tcx.lang_items() @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr) && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind && cx.typeck_results().expr_ty(receiver).is_bool() - && path.ident.name == sym!(then_some) + && path.ident.name.as_str() == "then_some" && is_local_with_projections(transmutable) && binops_with_local(cx, transmutable, receiver) && is_normalizable(cx, cx.param_env, from_ty) diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index dd45602221267..6b007e3030d6b 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -218,9 +218,7 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) { if let Some(value) = extract_clippy_version_value(cx, item) { - // The `sym!` macro doesn't work as it only expects a single token. - // It's better to keep it this way and have a direct `Symbol::intern` call here. - if value == Symbol::intern("pre 1.29.0") { + if value.as_str() == "pre 1.29.0" { return; } diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 63fcbd61528d2..6869224615303 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -42,7 +42,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) }) - && !items.iter().any(|item| item.ident.name == sym!(check_attributes)) + && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") { let context = if is_late_pass { "LateContext" } else { "EarlyContext" }; let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" }; diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index eb79fdbc4b4c8..8e7f020c1f659 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -1,6 +1,7 @@ #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( + clippy::slow_symbol_comparisons, clippy::borrow_deref_ref, clippy::unnecessary_operation, unused_must_use, diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index bbea13af92a54..9aeeb9aaf3aa3 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( + clippy::slow_symbol_comparisons, clippy::borrow_deref_ref, clippy::unnecessary_operation, unused_must_use, diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index 551167a9ff58b..668c11722f91c 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -1,5 +1,5 @@ error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:15:5 + --> tests/ui-internal/unnecessary_symbol_str.rs:16:5 | LL | Symbol::intern("foo").as_str() == "clippy"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy` @@ -12,25 +12,25 @@ LL | #![deny(clippy::internal)] = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]` error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:16:5 + --> tests/ui-internal/unnecessary_symbol_str.rs:17:5 | LL | Symbol::intern("foo").to_string() == "self"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower` error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:17:5 + --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 | LL | Symbol::intern("foo").to_ident_string() != "Self"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper` error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 + --> tests/ui-internal/unnecessary_symbol_str.rs:19:5 | LL | &*Ident::empty().as_str() == "clippy"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy` error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:19:5 + --> tests/ui-internal/unnecessary_symbol_str.rs:20:5 | LL | "clippy" == Ident::empty().to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` From a650692f8d53fb1ff3abf2ebb000721d1f4a4035 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sun, 13 Oct 2024 16:36:08 +0100 Subject: [PATCH 0048/1110] Add test --- .../ui-internal/slow_symbol_comparisons.fixed | 24 +++++++++++++++++++ tests/ui-internal/slow_symbol_comparisons.rs | 24 +++++++++++++++++++ .../slow_symbol_comparisons.stderr | 23 ++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 tests/ui-internal/slow_symbol_comparisons.fixed create mode 100644 tests/ui-internal/slow_symbol_comparisons.rs create mode 100644 tests/ui-internal/slow_symbol_comparisons.stderr diff --git a/tests/ui-internal/slow_symbol_comparisons.fixed b/tests/ui-internal/slow_symbol_comparisons.fixed new file mode 100644 index 0000000000000..2cbd646a0fd5d --- /dev/null +++ b/tests/ui-internal/slow_symbol_comparisons.fixed @@ -0,0 +1,24 @@ +#![feature(rustc_private)] +#![warn(clippy::slow_symbol_comparisons)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::Symbol; + +fn main() { + let symbol = sym!(example); + let other_symbol = sym!(other_example); + + // Should lint + let slow_comparison = symbol.as_str() == "example"; + //~^ error: comparing `Symbol` via `Symbol::intern` + let slow_comparison_macro = symbol.as_str() == "example"; + //~^ error: comparing `Symbol` via `Symbol::intern` + let slow_comparison_backwards = symbol.as_str() == "example"; + //~^ error: comparing `Symbol` via `Symbol::intern` + + // Should not lint + let faster_comparison = symbol.as_str() == "other_example"; + let preinterned_comparison = symbol == other_symbol; +} diff --git a/tests/ui-internal/slow_symbol_comparisons.rs b/tests/ui-internal/slow_symbol_comparisons.rs new file mode 100644 index 0000000000000..0cea3c3fcff9f --- /dev/null +++ b/tests/ui-internal/slow_symbol_comparisons.rs @@ -0,0 +1,24 @@ +#![feature(rustc_private)] +#![warn(clippy::slow_symbol_comparisons)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::Symbol; + +fn main() { + let symbol = sym!(example); + let other_symbol = sym!(other_example); + + // Should lint + let slow_comparison = symbol == Symbol::intern("example"); + //~^ error: comparing `Symbol` via `Symbol::intern` + let slow_comparison_macro = symbol == sym!(example); + //~^ error: comparing `Symbol` via `Symbol::intern` + let slow_comparison_backwards = sym!(example) == symbol; + //~^ error: comparing `Symbol` via `Symbol::intern` + + // Should not lint + let faster_comparison = symbol.as_str() == "other_example"; + let preinterned_comparison = symbol == other_symbol; +} diff --git a/tests/ui-internal/slow_symbol_comparisons.stderr b/tests/ui-internal/slow_symbol_comparisons.stderr new file mode 100644 index 0000000000000..72cb20a7fed90 --- /dev/null +++ b/tests/ui-internal/slow_symbol_comparisons.stderr @@ -0,0 +1,23 @@ +error: comparing `Symbol` via `Symbol::intern` + --> tests/ui-internal/slow_symbol_comparisons.rs:14:27 + | +LL | let slow_comparison = symbol == Symbol::intern("example"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` + | + = note: `-D clippy::slow-symbol-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::slow_symbol_comparisons)]` + +error: comparing `Symbol` via `Symbol::intern` + --> tests/ui-internal/slow_symbol_comparisons.rs:16:33 + | +LL | let slow_comparison_macro = symbol == sym!(example); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` + +error: comparing `Symbol` via `Symbol::intern` + --> tests/ui-internal/slow_symbol_comparisons.rs:18:37 + | +LL | let slow_comparison_backwards = sym!(example) == symbol; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` + +error: aborting due to 3 previous errors + From 979e2971897e8aa4a02d914a6336b5291a0839c7 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sun, 13 Oct 2024 18:44:21 +0100 Subject: [PATCH 0049/1110] Update book --- .../src/development/common_tools_writing_lints.md | 4 ++-- book/src/development/method_checking.md | 15 ++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 09171d86a2097..77910917963ee 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for MyStructLint { // Check our expr is calling a method if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind // Check the name of this method is `some_method` - && path.ident.name == sym!(some_method) + && path.ident.name.as_str() == "some_method" // Optionally, check the type of the self argument. // - See "Checking for a specific type" { @@ -167,7 +167,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { // Check if item is a method/function if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // Check the method is named `some_method` - && impl_item.ident.name == sym!(some_method) + && impl_item.ident.name.as_str() == "some_method" // We can also check it has a parameter `self` && signature.decl.implicit_self.has_implicit_self() // We can go further and even check if its return type is `String` diff --git a/book/src/development/method_checking.md b/book/src/development/method_checking.md index 56d1be37519e9..9c5d4b516db2c 100644 --- a/book/src/development/method_checking.md +++ b/book/src/development/method_checking.md @@ -3,8 +3,8 @@ In some scenarios we might want to check for methods when developing a lint. There are two kinds of questions that we might be curious about: -- Invocation: Does an expression call a specific method? -- Definition: Does an `impl` define a method? +- Invocation: Does an expression call a specific method? +- Definition: Does an `impl` define a method? ## Checking if an `expr` is calling a specific method @@ -23,7 +23,7 @@ impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint { // Check our expr is calling a method with pattern matching if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind // Check if the name of this method is `our_fancy_method` - && path.ident.name == sym!(our_fancy_method) + && path.ident.name.as_str() == "our_fancy_method" // We can check the type of the self argument whenever necessary. // (It's necessary if we want to check that method is specifically belonging to a specific trait, // for example, a `map` method could belong to user-defined trait instead of to `Iterator`) @@ -41,10 +41,6 @@ information on the pattern matching. As mentioned in [Define Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern matching with `MethodCall` in case the reader wishes to explore more. -Additionally, we use the [`clippy_utils::sym!`][sym] macro to conveniently -convert an input `our_fancy_method` into a `Symbol` and compare that symbol to -the [`Ident`]'s name in the [`PathSegment`] in the [`MethodCall`]. - ## Checking if a `impl` block implements a method While sometimes we want to check whether a method is being called or not, other @@ -71,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { // Check if item is a method/function if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // Check the method is named `our_fancy_method` - && impl_item.ident.name == sym!(our_fancy_method) + && impl_item.ident.name.as_str() == "our_fancy_method" // We can also check it has a parameter `self` && signature.decl.implicit_self.has_implicit_self() // We can go even further and even check if its return type is `String` @@ -85,9 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { [`check_impl_item`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_impl_item [`ExprKind`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html -[`Ident`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/struct.Ident.html [`ImplItem`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_hir/hir/struct.ImplItem.html [`LateLintPass`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html [`MethodCall`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html#variant.MethodCall -[`PathSegment`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/struct.PathSegment.html -[sym]: https://doc.rust-lang.org/stable/nightly-rustc/clippy_utils/macro.sym.html From d2cdc76256313e8f23f585107c43badb49d5473d Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Sun, 22 Sep 2024 16:58:44 -0700 Subject: [PATCH 0050/1110] Implement file_lock feature This adds lock(), lock_shared(), try_lock(), try_lock_shared(), and unlock() to File gated behind the file_lock feature flag --- library/std/src/fs.rs | 217 ++++++++++++++++++ library/std/src/fs/tests.rs | 80 +++++++ library/std/src/sys/pal/hermit/fs.rs | 20 ++ library/std/src/sys/pal/solid/fs.rs | 20 ++ library/std/src/sys/pal/unix/fs.rs | 37 +++ library/std/src/sys/pal/unsupported/fs.rs | 20 ++ library/std/src/sys/pal/wasi/fs.rs | 20 ++ .../std/src/sys/pal/windows/c/bindings.txt | 4 + .../std/src/sys/pal/windows/c/windows_sys.rs | 5 + library/std/src/sys/pal/windows/fs.rs | 88 +++++++ 10 files changed, 511 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index db7867337dd59..efe936843c8c6 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -615,6 +615,223 @@ impl File { self.inner.datasync() } + /// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired. + /// + /// This acquires an exclusive advisory lock; no other file handle to this file may acquire + /// another lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then an exclusive lock is held. + /// + /// If the file not open for writing, it is unspecified whether this function returns an error. + /// + /// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, + /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that, + /// this [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock_shared`]: File::lock_shared + /// [`try_lock`]: File::try_lock + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn lock(&self) -> io::Result<()> { + self.inner.lock() + } + + /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired. + /// + /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but + /// none may hold an exclusive lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then a shared lock is held. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, + /// and the `LockFileEx` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`try_lock`]: File::try_lock + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock_shared()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn lock_shared(&self) -> io::Result<()> { + self.inner.lock_shared() + } + + /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked. + /// + /// This acquires an exclusive advisory lock; no other file handle to this file may acquire + /// another lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then an exclusive lock is held. + /// + /// If the file not open for writing, it is unspecified whether this function returns an error. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and + /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` + /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`lock_shared`]: File::lock_shared + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.try_lock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn try_lock(&self) -> io::Result { + self.inner.try_lock() + } + + /// Acquire a shared advisory lock on the file. + /// Returns `Ok(false)` if the file is exclusively locked. + /// + /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but + /// none may hold an exclusive lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then a shared lock is held. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], + /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and + /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the + /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`lock_shared`]: File::lock_shared + /// [`try_lock`]: File::try_lock + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.try_lock_shared()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn try_lock_shared(&self) -> io::Result { + self.inner.try_lock_shared() + } + + /// Release all locks on the file. + /// + /// All remaining locks are released when the file handle, and all clones of it, are dropped. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_UN` flag, + /// and the `UnlockFile` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock()?; + /// f.unlock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn unlock(&self) -> io::Result<()> { + self.inner.unlock() + } + /// Truncates or extends the underlying file, updating the size of /// this file to become `size`. /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 0672fe6f7718a..fe3dc4adff0ba 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -203,6 +203,86 @@ fn file_test_io_seek_and_write() { assert!(read_str == final_msg); } +#[test] +fn file_lock_multiple_shared() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_multiple_shared_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that we can acquire concurrent shared locks + check!(f1.lock_shared()); + check!(f2.lock_shared()); + check!(f1.unlock()); + check!(f2.unlock()); + assert!(check!(f1.try_lock_shared())); + assert!(check!(f2.try_lock_shared())); +} + +#[test] +fn file_lock_blocking() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_blocking_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that shared locks block exclusive locks + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + check!(f1.unlock()); + + // Check that exclusive locks block shared locks + check!(f1.lock()); + assert!(!check!(f2.try_lock_shared())); +} + +#[test] +fn file_lock_drop() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_dup_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that locks are released when the File is dropped + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + drop(f1); + assert!(check!(f2.try_lock())); +} + +#[test] +fn file_lock_dup() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_dup_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that locks are not dropped if the File has been cloned + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + let cloned = check!(f1.try_clone()); + drop(f1); + assert!(!check!(f2.try_lock())); + drop(cloned) +} + +#[test] +#[cfg(windows)] +fn file_lock_double_unlock() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_double_unlock_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // On Windows a file handle may acquire both a shared and exclusive lock. + // Check that both are released by unlock() + check!(f1.lock()); + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + check!(f1.unlock()); + assert!(check!(f2.try_lock())); +} + #[test] fn file_test_io_seek_shakedown() { // 01234567890123 diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index 70f6981f7175b..17d15ed2e5045 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -364,6 +364,26 @@ impl File { self.fsync() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index bce9aa6d99cd1..776a96ff3b7ba 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -350,6 +350,26 @@ impl File { self.flush() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 39aabf0b2d679..865105421949d 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1254,6 +1254,43 @@ impl File { } } + pub fn lock(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?; + return Ok(()); + } + + pub fn lock_shared(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?; + return Ok(()); + } + + pub fn try_lock(&self) -> io::Result { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); + if let Err(ref err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + return Ok(false); + } + } + result?; + return Ok(true); + } + + pub fn try_lock_shared(&self) -> io::Result { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); + if let Err(ref err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + return Ok(false); + } + } + result?; + return Ok(true); + } + + pub fn unlock(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?; + return Ok(()); + } + pub fn truncate(&self, size: u64) -> io::Result<()> { let size: off64_t = size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs index 474c9fe97d18d..9585ec24f687d 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/pal/unsupported/fs.rs @@ -198,6 +198,26 @@ impl File { self.0 } + pub fn lock(&self) -> io::Result<()> { + self.0 + } + + pub fn lock_shared(&self) -> io::Result<()> { + self.0 + } + + pub fn try_lock(&self) -> io::Result { + self.0 + } + + pub fn try_lock_shared(&self) -> io::Result { + self.0 + } + + pub fn unlock(&self) -> io::Result<()> { + self.0 + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { self.0 } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 59ecc45b06a1f..3296c762cca2b 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -420,6 +420,26 @@ impl File { self.fd.datasync() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, size: u64) -> io::Result<()> { self.fd.filestat_set_size(size) } diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 9c2e4500da068..d54ec9820dcad 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2349,6 +2349,9 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW Windows.Win32.Storage.FileSystem.GetFullPathNameW Windows.Win32.Storage.FileSystem.GetTempPathW Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES +Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK +Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY +Windows.Win32.Storage.FileSystem.LockFileEx Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE_CALLBACK_REASON Windows.Win32.Storage.FileSystem.MAXIMUM_REPARSE_DATA_BUFFER_SIZE @@ -2394,6 +2397,7 @@ Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAG_DIRECTORY Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAGS Windows.Win32.Storage.FileSystem.SYNCHRONIZE Windows.Win32.Storage.FileSystem.TRUNCATE_EXISTING +Windows.Win32.Storage.FileSystem.UnlockFile Windows.Win32.Storage.FileSystem.VOLUME_NAME_DOS Windows.Win32.Storage.FileSystem.VOLUME_NAME_GUID Windows.Win32.Storage.FileSystem.VOLUME_NAME_NONE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index ab5f8919d7af6..f17320cfad581 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -65,6 +65,7 @@ windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinit windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); +windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); @@ -96,6 +97,7 @@ windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT); windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); @@ -2725,6 +2727,9 @@ pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, } +pub const LOCKFILE_EXCLUSIVE_LOCK: LOCK_FILE_FLAGS = 2u32; +pub const LOCKFILE_FAIL_IMMEDIATELY: LOCK_FILE_FLAGS = 1u32; +pub type LOCK_FILE_FLAGS = u32; pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option< unsafe extern "system" fn( dwerrorcode: u32, diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index aab471e28eaeb..bc728d498c3c3 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -346,6 +346,94 @@ impl File { self.fsync() } + pub fn lock(&self) -> io::Result<()> { + cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx( + self.handle.as_raw_handle(), + c::LOCKFILE_EXCLUSIVE_LOCK, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) + })?; + Ok(()) + } + + pub fn lock_shared(&self) -> io::Result<()> { + cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX, &mut overlapped) + })?; + Ok(()) + } + + pub fn try_lock(&self) -> io::Result { + let result = cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx( + self.handle.as_raw_handle(), + c::LOCKFILE_EXCLUSIVE_LOCK | c::LOCKFILE_FAIL_IMMEDIATELY, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) + }); + + if let Err(ref err) = result { + if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) + || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) + { + return Ok(false); + } + } + result?; + Ok(true) + } + + pub fn try_lock_shared(&self) -> io::Result { + let result = cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx( + self.handle.as_raw_handle(), + c::LOCKFILE_FAIL_IMMEDIATELY, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) + }); + + if let Err(ref err) = result { + if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) + || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) + { + return Ok(false); + } + } + result?; + Ok(true) + } + + pub fn unlock(&self) -> io::Result<()> { + // Unlock the handle twice because LockFileEx() allows a file handle to acquire + // both an exclusive and shared lock, in which case the documentation states that: + // "...two unlock operations are necessary to unlock the region; the first unlock operation + // unlocks the exclusive lock, the second unlock operation unlocks the shared lock" + cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) })?; + let result = + cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) }); + if let Err(ref err) = result { + if err.raw_os_error() == Some(c::ERROR_NOT_LOCKED as i32) { + return Ok(()); + } + } + result?; + Ok(()) + } + pub fn truncate(&self, size: u64) -> io::Result<()> { let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() From 11162d1b4808f85362048a816a0f5f4c79f2f747 Mon Sep 17 00:00:00 2001 From: wowinter13 Date: Tue, 15 Oct 2024 00:18:50 +0200 Subject: [PATCH 0051/1110] fix: remove unnecessary unfilter_map usages --- .../src/methods/unnecessary_filter_map.rs | 31 +++++++++-- tests/ui/unnecessary_filter_map.rs | 13 +++-- tests/ui/unnecessary_filter_map.stderr | 53 +++++++++++++------ tests/ui/unnecessary_find_map.rs | 9 ++-- tests/ui/unnecessary_find_map.stderr | 30 +++++------ 5 files changed, 92 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ca46da81fa053..33f073e75a616 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,13 +1,15 @@ use super::utils::clone_or_copy_needed; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use clippy_utils::{MaybePath, is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; +use rustc_middle::query::Key; use rustc_middle::ty; use rustc_span::sym; @@ -36,9 +38,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a ControlFlow::Continue(Descend::Yes) } }); - let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let sugg = if !found_filtering { + // Check if the closure is .filter_map(|x| Some(x)) + if name == "filter_map" + && let hir::ExprKind::Call(expr, args) = body.value.kind + && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome) + && arg_id.ty_def_id() == args[0].hir_id().ty_def_id() + && let hir::ExprKind::Path(_) = args[0].kind + { + span_lint_and_sugg( + cx, + UNNECESSARY_FILTER_MAP, + expr.span, + format!("{name} is unnecessary"), + "try removing the filter_map", + String::new(), + Applicability::MaybeIncorrect, + ); + } if name == "filter_map" { "map" } else { "map(..).next()" } } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) { match cx.typeck_results().expr_ty(body.value).kind() { @@ -52,7 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a } else { return; }; - span_lint( + span_lint_and_sugg( cx, if name == "filter_map" { UNNECESSARY_FILTER_MAP @@ -60,7 +78,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a UNNECESSARY_FIND_MAP }, expr.span, - format!("this `.{name}` can be written more simply using `.{sugg}`"), + format!("this `.{name}` can be written more simply"), + format!("try replacing with `.{sugg}`"), + sugg.to_string(), + Applicability::MaybeIncorrect, ); } } diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs index 1e0d7d12965c2..8cf102ab0a557 100644 --- a/tests/ui/unnecessary_filter_map.rs +++ b/tests/ui/unnecessary_filter_map.rs @@ -1,26 +1,31 @@ +//@no-rustfix #![allow(dead_code)] fn main() { let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - //~^ ERROR: this `.filter_map` can be written more simply using `.filter` + //~^ ERROR: this `.filter_map` can be written more simply //~| NOTE: `-D clippy::unnecessary-filter-map` implied by `-D warnings` let _ = (0..4).filter_map(|x| { - //~^ ERROR: this `.filter_map` can be written more simply using `.filter` + //~^ ERROR: this `.filter_map` can be written more simply if x > 1 { return Some(x); }; None }); let _ = (0..4).filter_map(|x| match x { - //~^ ERROR: this `.filter_map` can be written more simply using `.filter` + //~^ ERROR: this `.filter_map` can be written more simply 0 | 1 => None, _ => Some(x), }); let _ = (0..4).filter_map(|x| Some(x + 1)); - //~^ ERROR: this `.filter_map` can be written more simply using `.map` + //~^ ERROR: this `.filter_map` can be written more simply let _ = (0..4).filter_map(i32::checked_abs); + + let _ = (0..4).filter_map(Some); + + let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); } fn filter_map_none_changes_item_type() -> impl Iterator { diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr index f32d444ba9e09..7ef3d970420b8 100644 --- a/tests/ui/unnecessary_filter_map.stderr +++ b/tests/ui/unnecessary_filter_map.stderr @@ -1,14 +1,14 @@ -error: this `.filter_map` can be written more simply using `.filter` - --> tests/ui/unnecessary_filter_map.rs:4:13 +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:5:13 | LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.filter`: `filter` | = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_filter_map)]` -error: this `.filter_map` can be written more simply using `.filter` - --> tests/ui/unnecessary_filter_map.rs:7:13 +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:8:13 | LL | let _ = (0..4).filter_map(|x| { | _____________^ @@ -18,10 +18,10 @@ LL | | return Some(x); LL | | }; LL | | None LL | | }); - | |______^ + | |______^ help: try replacing with `.filter`: `filter` -error: this `.filter_map` can be written more simply using `.filter` - --> tests/ui/unnecessary_filter_map.rs:14:13 +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:15:13 | LL | let _ = (0..4).filter_map(|x| match x { | _____________^ @@ -29,19 +29,40 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ + | |______^ help: try replacing with `.filter`: `filter` -error: this `.filter_map` can be written more simply using `.map` - --> tests/ui/unnecessary_filter_map.rs:20:13 +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:21:13 | LL | let _ = (0..4).filter_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map`: `map` -error: this `.filter_map` can be written more simply using `.filter` - --> tests/ui/unnecessary_filter_map.rs:160:14 +error: redundant closure + --> tests/ui/unnecessary_filter_map.rs:28:57 + | +LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); + | ^^^^^^^^^^^ help: replace the closure with the function itself: `Some` + | + = note: `-D clippy::redundant-closure` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` + +error: filter_map is unnecessary + --> tests/ui/unnecessary_filter_map.rs:28:61 + | +LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); + | ^^^^ help: try removing the filter_map + +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:28:13 + | +LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map`: `map` + +error: this `.filter_map` can be written more simply + --> tests/ui/unnecessary_filter_map.rs:165:14 | LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.filter`: `filter` -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/unnecessary_find_map.rs b/tests/ui/unnecessary_find_map.rs index 9972b68092abf..c357d85324819 100644 --- a/tests/ui/unnecessary_find_map.rs +++ b/tests/ui/unnecessary_find_map.rs @@ -1,24 +1,25 @@ +//@no-rustfix #![allow(dead_code)] fn main() { let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); - //~^ ERROR: this `.find_map` can be written more simply using `.find` + //~^ ERROR: this `.find_map` can be written more simply //~| NOTE: `-D clippy::unnecessary-find-map` implied by `-D warnings` let _ = (0..4).find_map(|x| { - //~^ ERROR: this `.find_map` can be written more simply using `.find` + //~^ ERROR: this `.find_map` can be written more simply if x > 1 { return Some(x); }; None }); let _ = (0..4).find_map(|x| match x { - //~^ ERROR: this `.find_map` can be written more simply using `.find` + //~^ ERROR: this `.find_map` can be written more simply 0 | 1 => None, _ => Some(x), }); let _ = (0..4).find_map(|x| Some(x + 1)); - //~^ ERROR: this `.find_map` can be written more simply using `.map(..).next()` + //~^ ERROR: this `.find_map` can be written more simply let _ = (0..4).find_map(i32::checked_abs); } diff --git a/tests/ui/unnecessary_find_map.stderr b/tests/ui/unnecessary_find_map.stderr index bb939a9921467..650b6d64d35b7 100644 --- a/tests/ui/unnecessary_find_map.stderr +++ b/tests/ui/unnecessary_find_map.stderr @@ -1,14 +1,14 @@ -error: this `.find_map` can be written more simply using `.find` - --> tests/ui/unnecessary_find_map.rs:4:13 +error: this `.find_map` can be written more simply + --> tests/ui/unnecessary_find_map.rs:5:13 | LL | let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.find`: `find` | = note: `-D clippy::unnecessary-find-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_find_map)]` -error: this `.find_map` can be written more simply using `.find` - --> tests/ui/unnecessary_find_map.rs:7:13 +error: this `.find_map` can be written more simply + --> tests/ui/unnecessary_find_map.rs:8:13 | LL | let _ = (0..4).find_map(|x| { | _____________^ @@ -18,10 +18,10 @@ LL | | return Some(x); LL | | }; LL | | None LL | | }); - | |______^ + | |______^ help: try replacing with `.find`: `find` -error: this `.find_map` can be written more simply using `.find` - --> tests/ui/unnecessary_find_map.rs:14:13 +error: this `.find_map` can be written more simply + --> tests/ui/unnecessary_find_map.rs:15:13 | LL | let _ = (0..4).find_map(|x| match x { | _____________^ @@ -29,19 +29,19 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ + | |______^ help: try replacing with `.find`: `find` -error: this `.find_map` can be written more simply using `.map(..).next()` - --> tests/ui/unnecessary_find_map.rs:20:13 +error: this `.find_map` can be written more simply + --> tests/ui/unnecessary_find_map.rs:21:13 | LL | let _ = (0..4).find_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map(..).next()`: `map(..).next()` -error: this `.find_map` can be written more simply using `.find` - --> tests/ui/unnecessary_find_map.rs:32:14 +error: this `.find_map` can be written more simply + --> tests/ui/unnecessary_find_map.rs:33:14 | LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.find`: `find` error: aborting due to 5 previous errors From 40cb24f23c9b74bba8009d0dfe8ef84d265e4d9c Mon Sep 17 00:00:00 2001 From: wowinter13 Date: Wed, 16 Oct 2024 01:42:43 +0200 Subject: [PATCH 0052/1110] fix: simplify suggestion --- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- tests/ui/unnecessary_filter_map.stderr | 12 ++++++------ tests/ui/unnecessary_find_map.stderr | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 33f073e75a616..49d5d7318f696 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -79,7 +79,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a }, expr.span, format!("this `.{name}` can be written more simply"), - format!("try replacing with `.{sugg}`"), + format!("try instead"), sugg.to_string(), Applicability::MaybeIncorrect, ); diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr index 7ef3d970420b8..b21589c5f8445 100644 --- a/tests/ui/unnecessary_filter_map.stderr +++ b/tests/ui/unnecessary_filter_map.stderr @@ -2,7 +2,7 @@ error: this `.filter_map` can be written more simply --> tests/ui/unnecessary_filter_map.rs:5:13 | LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.filter`: `filter` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter` | = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_filter_map)]` @@ -18,7 +18,7 @@ LL | | return Some(x); LL | | }; LL | | None LL | | }); - | |______^ help: try replacing with `.filter`: `filter` + | |______^ help: try instead: `filter` error: this `.filter_map` can be written more simply --> tests/ui/unnecessary_filter_map.rs:15:13 @@ -29,13 +29,13 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ help: try replacing with `.filter`: `filter` + | |______^ help: try instead: `filter` error: this `.filter_map` can be written more simply --> tests/ui/unnecessary_filter_map.rs:21:13 | LL | let _ = (0..4).filter_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map`: `map` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` error: redundant closure --> tests/ui/unnecessary_filter_map.rs:28:57 @@ -56,13 +56,13 @@ error: this `.filter_map` can be written more simply --> tests/ui/unnecessary_filter_map.rs:28:13 | LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map`: `map` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` error: this `.filter_map` can be written more simply --> tests/ui/unnecessary_filter_map.rs:165:14 | LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.filter`: `filter` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter` error: aborting due to 8 previous errors diff --git a/tests/ui/unnecessary_find_map.stderr b/tests/ui/unnecessary_find_map.stderr index 650b6d64d35b7..98a6c3d164a63 100644 --- a/tests/ui/unnecessary_find_map.stderr +++ b/tests/ui/unnecessary_find_map.stderr @@ -2,7 +2,7 @@ error: this `.find_map` can be written more simply --> tests/ui/unnecessary_find_map.rs:5:13 | LL | let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.find`: `find` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find` | = note: `-D clippy::unnecessary-find-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_find_map)]` @@ -18,7 +18,7 @@ LL | | return Some(x); LL | | }; LL | | None LL | | }); - | |______^ help: try replacing with `.find`: `find` + | |______^ help: try instead: `find` error: this `.find_map` can be written more simply --> tests/ui/unnecessary_find_map.rs:15:13 @@ -29,19 +29,19 @@ LL | | LL | | 0 | 1 => None, LL | | _ => Some(x), LL | | }); - | |______^ help: try replacing with `.find`: `find` + | |______^ help: try instead: `find` error: this `.find_map` can be written more simply --> tests/ui/unnecessary_find_map.rs:21:13 | LL | let _ = (0..4).find_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.map(..).next()`: `map(..).next()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map(..).next()` error: this `.find_map` can be written more simply --> tests/ui/unnecessary_find_map.rs:33:14 | LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing with `.find`: `find` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find` error: aborting due to 5 previous errors From ad002ea99f5e5ca6e47a9550964bf0a882083e5b Mon Sep 17 00:00:00 2001 From: wowinter13 Date: Wed, 16 Oct 2024 01:49:15 +0200 Subject: [PATCH 0053/1110] fix: linter --- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 49d5d7318f696..264363aadfbc8 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -79,7 +79,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a }, expr.span, format!("this `.{name}` can be written more simply"), - format!("try instead"), + "try instead", sugg.to_string(), Applicability::MaybeIncorrect, ); From e3029abfaec4252ab0ae7010780be0094d8870e0 Mon Sep 17 00:00:00 2001 From: VulnBandit <183613941+VulnBandit@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:11:16 +0200 Subject: [PATCH 0054/1110] Improve duplicate derive Copy/Clone diagnostics --- .../src/diagnostics/move_errors.rs | 17 ++++++++++++++ ...duplicate-derive-copy-clone-diagnostics.rs | 11 +++++++++ ...icate-derive-copy-clone-diagnostics.stderr | 23 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3871816777c7f..15cc9c20ab7dc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::MirBorrowckCtxt; @@ -267,6 +268,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind, self.is_upvar_field_projection(original_path.as_ref()) ); + if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) { + // If the type may implement Copy, skip the error. + // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check + self.dcx().span_delayed_bug( + span, + "Type may implement copy, but there is no other error.", + ); + return; + } ( match kind { &IllegalMoveOriginKind::BorrowedContent { target_place } => self @@ -291,6 +301,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.buffer_error(err); } + fn has_ambiguous_copy(&mut self, ty: Ty<'tcx>) -> bool { + let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false }; + // This is only going to be ambiguous if there are incoherent impls, because otherwise + // ambiguity should never happen in MIR. + self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply() + } + fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs new file mode 100644 index 0000000000000..c4fb620fea4f3 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs @@ -0,0 +1,11 @@ +// Duplicate implementations of Copy/Clone should not trigger +// borrow check warnings +// See #131083 + +#[derive(Copy, Clone)] +#[derive(Copy, Clone)] +//~^ ERROR conflicting implementations of trait `Clone` for type `E` +//~| ERROR conflicting implementations of trait `Copy` for type `E` +enum E {} + +fn main() {} diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr new file mode 100644 index 0000000000000..f8e1db33f5363 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr @@ -0,0 +1,23 @@ +error[E0119]: conflicting implementations of trait `Copy` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:10 + | +LL | #[derive(Copy, Clone)] + | ---- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `Clone` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 + | +LL | #[derive(Copy, Clone)] + | ----- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. From 47a7e994f2b7d8663b0559bc9327190fefe9e4ef Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:55:09 +0000 Subject: [PATCH 0055/1110] Rustup to rustc 1.84.0-nightly (798fb83f7 2024-10-16) --- patches/0022-coretests-Disable-not-compiling-tests.patch | 2 +- patches/0027-coretests-128bit-atomic-operations.patch | 2 +- patches/0028-coretests-Disable-long-running-tests.patch | 2 +- rust-toolchain | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/patches/0022-coretests-Disable-not-compiling-tests.patch b/patches/0022-coretests-Disable-not-compiling-tests.patch index 5117b04fd3447..161173d47650f 100644 --- a/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644 @@ -1,3 +1,4 @@ +#![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(const_mut_refs))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] + #![cfg_attr(test, feature(cfg_match))] -- 2.21.0 (Apple Git-122) diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-coretests-128bit-atomic-operations.patch index efd721d9df885..5f5baae2fd655 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-coretests-128bit-atomic-operations.patch @@ -17,10 +17,10 @@ index 1e336bf..35e6f54 100644 @@ -1,6 +1,5 @@ #![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(const_mut_refs))] -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] + #![feature(array_chunks)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/patches/0028-coretests-Disable-long-running-tests.patch b/patches/0028-coretests-Disable-long-running-tests.patch index d7204add7a788..5009b24c9d08f 100644 --- a/patches/0028-coretests-Disable-long-running-tests.patch +++ b/patches/0028-coretests-Disable-long-running-tests.patch @@ -12,7 +12,7 @@ index 8402833..84592e0 100644 --- a/slice.rs +++ b/slice.rs @@ -1809,6 +1809,7 @@ fn sort_unstable() { - assert!(v == [0xDEADBEEF]); + } } +/* diff --git a/rust-toolchain b/rust-toolchain index 775402b2b5eba..0aa0f9e21cbff 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-10-10" +channel = "nightly-2024-10-17" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 16067fdea148adb7ad6c1414f0c253dc0592d809 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:57:34 +0200 Subject: [PATCH 0056/1110] Mark blocks as cold in a couple more places --- src/base.rs | 4 +++- src/intrinsics/mod.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index f336198947290..5d860bf6e0e20 100644 --- a/src/base.rs +++ b/src/base.rs @@ -379,7 +379,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let target = fx.get_block(*target); let failure = fx.bcx.create_block(); - fx.bcx.set_cold_block(failure); if *expected { fx.bcx.ins().brif(cond, target, &[], failure, &[]); @@ -544,6 +543,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } TerminatorKind::Unreachable => { + fx.bcx.set_cold_block(block); fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } TerminatorKind::Yield { .. } @@ -1075,6 +1075,8 @@ fn codegen_panic_inner<'tcx>( args: &[Value], span: Option, ) { + fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); + let def_id = fx.tcx.require_lang_item(lang_item, span); let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 35f0ccff3f99e..e96ab1e90a21d 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -449,6 +449,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match intrinsic { sym::abort => { + fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); fx.bcx.ins().trap(TrapCode::User(0)); return Ok(()); } From bbaaecc250a8601a756686e72a97d463968282a4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:31:12 +0000 Subject: [PATCH 0057/1110] Stop copying libstd.so to dist/lib It is only necessary in dist/lib/rustlib/*/lib anymore. The jit mode now correctly find it there too. --- build_system/build_sysroot.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 82558999aface..f1f4489bcbc8d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -102,15 +102,6 @@ pub(crate) fn build_sysroot( .install_into_sysroot(&dist_dir); } - // Copy std for the host to the lib dir. This is necessary for the jit mode to find - // libstd. - for lib in host.libs { - let filename = lib.file_name().unwrap().to_str().unwrap(); - if filename.contains("std-") && !filename.contains(".rlib") { - try_hard_link(&lib, dist_dir.join("lib").join(lib.file_name().unwrap())); - } - } - let mut target_compiler = { let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")); let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")); From 6666435b8ad7045446e170b155c4e419338c545a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:58:00 +0000 Subject: [PATCH 0058/1110] Fix rustc test suite (broken by prev commit) --- scripts/test_rustc_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index fbf4ce0223416..035034e0fab85 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -145,6 +145,7 @@ rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist +cp $(../dist/rustc-clif --print target-libdir)/libstd-*.so ../dist/lib/ # prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by # rustdoc-clif From 85559223519ee0d72fa90dc48d92faab36758bd0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 17 Oct 2024 22:36:26 +0500 Subject: [PATCH 0059/1110] Don't trigger const_is_empty for inline const assertions --- clippy_lints/src/methods/is_empty.rs | 13 ++++++++++++- tests/ui/const_is_empty.rs | 14 ++++++++++++++ tests/ui/const_is_empty.stderr | 8 +++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index cc82f6cfd6384..a0c21faaa4cc8 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -1,6 +1,7 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{find_binding_init, path_to_local}; +use clippy_utils::macros::{is_assert_macro, root_macro_call}; +use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; @@ -14,6 +15,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) { return; } + if let Some(parent) = get_parent_expr(cx, expr) { + if let Some(parent) = get_parent_expr(cx, parent) { + if is_inside_always_const_context(cx.tcx, expr.hir_id) + && let Some(macro_call) = root_macro_call(parent.span) + && is_assert_macro(cx, macro_call.def_id) + { + return; + } + } + } let init_expr = expr_or_init(cx, receiver); if !receiver.span.eq_ctxt(init_expr.span) { return; diff --git a/tests/ui/const_is_empty.rs b/tests/ui/const_is_empty.rs index 04e0de91ecfbf..b5e27b61548a0 100644 --- a/tests/ui/const_is_empty.rs +++ b/tests/ui/const_is_empty.rs @@ -171,3 +171,17 @@ fn constant_from_external_crate() { let _ = std::env::consts::EXE_EXTENSION.is_empty(); // Do not lint, `exe_ext` comes from the `std` crate } + +fn issue_13106() { + const { + assert!(!NON_EMPTY_STR.is_empty()); + } + + const { + assert!(EMPTY_STR.is_empty()); + } + + const { + EMPTY_STR.is_empty(); + } +} diff --git a/tests/ui/const_is_empty.stderr b/tests/ui/const_is_empty.stderr index 7f80b520b1a44..0afba940d8b4b 100644 --- a/tests/ui/const_is_empty.stderr +++ b/tests/ui/const_is_empty.stderr @@ -157,5 +157,11 @@ error: this expression always evaluates to true LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:185:9 + | +LL | EMPTY_STR.is_empty(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 27 previous errors From 2f1b15f145a04e08bebbde522c9ece8f0cad3706 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Aug 2023 00:31:26 +0000 Subject: [PATCH 0060/1110] Allow dropping dyn principal --- src/unsize.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unsize.rs b/src/unsize.rs index 5c297ebfadbfd..336934354e11b 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -34,7 +34,9 @@ pub(crate) fn unsized_info<'tcx>( { 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() { + let b_principal_def_id = data_b.principal_def_id(); + if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() { + // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. debug_assert!( validate_trivial_unsize(fx.tcx, data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" From 64ec068ca1e9581a57672cd6377cd45f7bd0abb7 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 18 Oct 2024 10:57:45 +0000 Subject: [PATCH 0061/1110] Revert using `HEAP` static in Windows alloc --- library/std/src/sys/alloc/windows.rs | 69 +++++----------------------- 1 file changed, 12 insertions(+), 57 deletions(-) diff --git a/library/std/src/sys/alloc/windows.rs b/library/std/src/sys/alloc/windows.rs index a77dda6e817ba..7e2402afab972 100644 --- a/library/std/src/sys/alloc/windows.rs +++ b/library/std/src/sys/alloc/windows.rs @@ -3,7 +3,6 @@ use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::mem::MaybeUninit; use crate::ptr; -use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys::c; #[cfg(test)] @@ -81,40 +80,18 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL); -// Cached handle to the default heap of the current process. -// Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. -static HEAP: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -// Get a handle to the default heap of the current process, or null if the operation fails. -// If this operation is successful, `HEAP` will be successfully initialized and contain -// a non-null handle returned by `GetProcessHeap`. -#[inline] -fn init_or_get_process_heap() -> c::HANDLE { - // `HEAP` has not yet been successfully initialized - let heap = unsafe { GetProcessHeap() }; - if !heap.is_null() { - // SAFETY: No locking is needed because within the same process, - // successful calls to `GetProcessHeap` will always return the same value, even on different threads. - HEAP.store(heap, Ordering::Release); - - // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` - heap - } else { - // Could not get the current process heap. - ptr::null_mut() - } +fn get_process_heap() -> *mut c_void { + // SAFETY: GetProcessHeap simply returns a valid handle or NULL so is always safe to call. + unsafe { GetProcessHeap() } } -/// This is outlined from `process_heap_alloc` so that `process_heap_alloc` -/// does not need any stack allocations. #[inline(never)] -#[cold] -extern "C" fn process_heap_init_and_alloc( - _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` +fn process_heap_alloc( + _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, flags: u32, bytes: usize, ) -> *mut c_void { - let heap = init_or_get_process_heap(); + let heap = get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { return ptr::null_mut(); } @@ -122,28 +99,6 @@ extern "C" fn process_heap_init_and_alloc( unsafe { HeapAlloc(heap, flags, bytes) } } -#[inline(never)] -fn process_heap_alloc( - _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, - flags: u32, - bytes: usize, -) -> *mut c_void { - let heap = HEAP.load(Ordering::Relaxed); - if core::intrinsics::likely(!heap.is_null()) { - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. - unsafe { HeapAlloc(heap, flags, bytes) } - } else { - process_heap_init_and_alloc(MaybeUninit::uninit(), flags, bytes) - } -} - -// Get a non-null handle to the default heap of the current process. -// SAFETY: `HEAP` must have been successfully initialized. -#[inline] -unsafe fn get_process_heap() -> c::HANDLE { - HEAP.load(Ordering::Acquire) -} - // Header containing a pointer to the start of an allocated block. // SAFETY: Size and alignment must be <= `MIN_ALIGN`. #[repr(C)] @@ -232,9 +187,9 @@ unsafe impl GlobalAlloc for System { } }; - // SAFETY: because `ptr` has been successfully allocated with this allocator, - // `HEAP` must have been successfully initialized. - let heap = unsafe { get_process_heap() }; + // because `ptr` has been successfully allocated with this allocator, + // there must be a valid process heap. + let heap = get_process_heap(); // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `block` is a pointer to the start of an allocated block. @@ -244,9 +199,9 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN { - // SAFETY: because `ptr` has been successfully allocated with this allocator, - // `HEAP` must have been successfully initialized. - let heap = unsafe { get_process_heap() }; + // because `ptr` has been successfully allocated with this allocator, + // there must be a valid process heap. + let heap = get_process_heap(); // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `ptr` is a pointer to the start of an allocated block. From fea5e77da1dedea3a64711cb1b75c141e72ba248 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 18 Oct 2024 13:44:06 +0200 Subject: [PATCH 0062/1110] Merge commit 'a109190d7060236e655fc75533373fa274ec5343' into clippy-subtree-update --- .github/deploy.sh | 2 +- .gitignore | 1 + CHANGELOG.md | 42 +- Cargo.toml | 8 +- book/src/lint_configuration.md | 2 +- clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 26 +- clippy_config/src/lib.rs | 2 +- clippy_config/src/msrvs.rs | 3 +- clippy_dev/Cargo.toml | 2 +- clippy_dev/src/new_lint.rs | 24 +- clippy_dev/src/serve.rs | 4 +- clippy_lints/Cargo.toml | 3 +- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/byte_char_slices.rs | 2 +- .../src/casts/cast_abs_to_unsigned.rs | 2 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/create_dir.rs | 2 +- clippy_lints/src/declare_clippy_lint.rs | 162 +++ clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/default.rs | 4 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 4 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 25 +- clippy_lints/src/implied_bounds_in_impls.rs | 4 +- clippy_lints/src/item_name_repetitions.rs | 35 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 19 +- clippy_lints/src/len_zero.rs | 18 +- clippy_lints/src/lib.rs | 17 +- clippy_lints/src/lifetimes.rs | 4 +- clippy_lints/src/literal_representation.rs | 1 - clippy_lints/src/loops/infinite_loop.rs | 19 +- .../src/loops/manual_while_let_some.rs | 11 +- clippy_lints/src/loops/same_item_push.rs | 6 +- clippy_lints/src/macro_use.rs | 1 - clippy_lints/src/main_recursion.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 22 +- clippy_lints/src/manual_ignore_case_cmp.rs | 127 ++ clippy_lints/src/manual_is_power_of_two.rs | 10 +- .../src/manual_slice_size_calculation.rs | 18 +- clippy_lints/src/manual_string_new.rs | 19 +- .../src/matches/redundant_pattern_match.rs | 2 +- clippy_lints/src/matches/try_err.rs | 4 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 4 +- clippy_lints/src/methods/iter_filter.rs | 4 +- .../src/methods/manual_c_str_literals.rs | 5 +- .../methods/manual_saturating_arithmetic.rs | 3 +- clippy_lints/src/methods/map_clone.rs | 3 +- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/methods/needless_collect.rs | 5 +- clippy_lints/src/methods/or_fun_call.rs | 4 +- .../src/methods/read_line_without_trim.rs | 3 +- .../src/methods/readonly_write_lock.rs | 2 +- clippy_lints/src/methods/seek_from_current.rs | 5 +- .../seek_to_start_instead_of_rewind.rs | 5 +- .../src/methods/single_char_insert_string.rs | 2 +- .../src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- .../src/methods/uninit_assumed_init.rs | 3 +- .../methods/unnecessary_first_then_check.rs | 2 +- clippy_lints/src/methods/useless_asref.rs | 5 +- .../src/missing_asserts_for_indexing.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/mut_key.rs | 13 +- clippy_lints/src/mut_reference.rs | 6 +- clippy_lints/src/needless_maybe_sized.rs | 2 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/non_zero_suggestions.rs | 2 +- clippy_lints/src/operators/float_cmp.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 2 +- clippy_lints/src/ptr.rs | 8 +- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/question_mark.rs | 7 +- clippy_lints/src/raw_strings.rs | 192 +-- clippy_lints/src/rc_clone_in_vec_init.rs | 4 +- clippy_lints/src/regex.rs | 65 +- clippy_lints/src/returns.rs | 2 +- .../src/significant_drop_tightening.rs | 3 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- .../src/slow_vector_initialization.rs | 4 +- clippy_lints/src/strings.rs | 11 +- clippy_lints/src/to_digit_is_some.rs | 5 +- clippy_lints/src/trait_bounds.rs | 96 +- clippy_lints/src/unit_types/unit_arg.rs | 9 +- clippy_lints/src/unnecessary_literal_bound.rs | 158 +++ .../src/unnecessary_map_on_constructor.rs | 10 +- .../src/unnecessary_owned_empty_strings.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 4 +- clippy_lints/src/unused_result_ok.rs | 2 +- clippy_lints/src/unwrap.rs | 9 +- clippy_lints/src/useless_conversion.rs | 4 +- .../utils/internal_lints/collapsible_calls.rs | 31 +- .../internal_lints/lint_without_lint_pass.rs | 8 +- clippy_lints/src/vec.rs | 3 +- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/consts.rs | 5 +- clippy_utils/src/hir_utils.rs | 119 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/ty.rs | 48 +- declare_clippy_lint/Cargo.toml | 13 - declare_clippy_lint/src/lib.rs | 182 --- lintcheck/ci_crates.toml | 18 +- lintcheck/src/json.rs | 2 +- rinja.toml | 3 + rust-toolchain | 2 +- rustc_tools_util/CHANGELOG.md | 9 + rustc_tools_util/Cargo.toml | 2 +- rustc_tools_util/README.md | 4 +- rustc_tools_util/src/lib.rs | 75 +- tests/compile-test.rs | 41 +- tests/config-metadata.rs | 4 +- .../array_size_threshold.stderr | 14 +- .../allowed_prefixes/item_name_repetitions.rs | 2 +- .../item_name_repetitions.rs | 2 +- tests/ui/expect_fun_call.stderr | 30 +- tests/ui/implicit_saturating_sub.fixed | 6 + tests/ui/implicit_saturating_sub.rs | 10 + tests/ui/implicit_saturating_sub.stderr | 13 +- tests/ui/infinite_loops.rs | 38 + tests/ui/infinite_loops.stderr | 64 +- tests/ui/invalid_null_ptr_usage.fixed | 44 +- tests/ui/invalid_null_ptr_usage.stderr | 44 +- tests/ui/invalid_null_ptr_usage_no_std.fixed | 57 + tests/ui/invalid_null_ptr_usage_no_std.rs | 57 + tests/ui/invalid_null_ptr_usage_no_std.stderr | 136 +++ tests/ui/large_const_arrays.fixed | 18 +- tests/ui/large_const_arrays.rs | 18 +- tests/ui/large_stack_arrays.rs | 44 +- tests/ui/large_stack_arrays.stderr | 48 +- ...> manual_c_str_literals.edition2021.fixed} | 3 + ... manual_c_str_literals.edition2021.stderr} | 26 +- tests/ui/manual_c_str_literals.rs | 3 + tests/ui/manual_float_methods.rs | 5 +- tests/ui/manual_float_methods.stderr | 8 +- tests/ui/manual_ignore_case_cmp.fixed | 107 ++ tests/ui/manual_ignore_case_cmp.rs | 107 ++ tests/ui/manual_ignore_case_cmp.stderr | 546 +++++++++ tests/ui/manual_slice_size_calculation.fixed | 4 + tests/ui/manual_slice_size_calculation.rs | 4 + tests/ui/manual_slice_size_calculation.stderr | 26 +- tests/ui/module_name_repetitions.rs | 18 +- tests/ui/module_name_repetitions.stderr | 8 +- tests/ui/mut_key.stderr | 60 + tests/ui/needless_raw_string.fixed | 9 + tests/ui/needless_raw_string.rs | 9 + tests/ui/needless_raw_string.stderr | 38 +- tests/ui/needless_raw_string_hashes.fixed | 10 + tests/ui/needless_raw_string_hashes.rs | 10 + tests/ui/needless_raw_string_hashes.stderr | 38 +- tests/ui/or_fun_call.fixed | 10 +- tests/ui/or_fun_call.rs | 10 +- tests/ui/or_fun_call.stderr | 40 +- tests/ui/regex.rs | 30 +- tests/ui/regex.stderr | 52 +- tests/ui/trait_duplication_in_bounds.fixed | 31 + tests/ui/trait_duplication_in_bounds.rs | 31 + tests/ui/trait_duplication_in_bounds.stderr | 32 +- .../transmutes_expressible_as_ptr_casts.fixed | 5 +- .../ui/transmutes_expressible_as_ptr_casts.rs | 5 +- tests/ui/unnecessary_literal_bound.fixed | 65 + tests/ui/unnecessary_literal_bound.rs | 65 + tests/ui/unnecessary_literal_bound.stderr | 23 + tests/ui/unwrap_or.fixed | 4 +- tests/ui/unwrap_or.rs | 4 +- tests/ui/unwrap_or.stderr | 4 +- tests/versioncheck.rs | 1 - triagebot.toml | 1 + util/gh-pages/index.html | 330 ------ util/gh-pages/index_template.html | 232 ++++ util/gh-pages/script.js | 1050 ++++++++--------- util/gh-pages/style.css | 51 +- util/gh-pages/theme.js | 56 + 179 files changed, 4025 insertions(+), 1745 deletions(-) create mode 100644 clippy_lints/src/declare_clippy_lint.rs create mode 100644 clippy_lints/src/manual_ignore_case_cmp.rs create mode 100644 clippy_lints/src/unnecessary_literal_bound.rs delete mode 100644 declare_clippy_lint/Cargo.toml delete mode 100644 declare_clippy_lint/src/lib.rs create mode 100644 rinja.toml create mode 100644 tests/ui/invalid_null_ptr_usage_no_std.fixed create mode 100644 tests/ui/invalid_null_ptr_usage_no_std.rs create mode 100644 tests/ui/invalid_null_ptr_usage_no_std.stderr rename tests/ui/{manual_c_str_literals.fixed => manual_c_str_literals.edition2021.fixed} (93%) rename tests/ui/{manual_c_str_literals.stderr => manual_c_str_literals.edition2021.stderr} (84%) create mode 100644 tests/ui/manual_ignore_case_cmp.fixed create mode 100644 tests/ui/manual_ignore_case_cmp.rs create mode 100644 tests/ui/manual_ignore_case_cmp.stderr create mode 100644 tests/ui/unnecessary_literal_bound.fixed create mode 100644 tests/ui/unnecessary_literal_bound.rs create mode 100644 tests/ui/unnecessary_literal_bound.stderr delete mode 100644 util/gh-pages/index.html create mode 100644 util/gh-pages/index_template.html create mode 100644 util/gh-pages/theme.js diff --git a/.github/deploy.sh b/.github/deploy.sh index 5b4b4be4e36b5..ea118a3b6fce5 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -8,8 +8,8 @@ rm -rf out/master/ || exit 0 echo "Making the docs for master" mkdir out/master/ cp util/gh-pages/index.html out/master +cp util/gh-pages/theme.js out/master cp util/gh-pages/script.js out/master -cp util/gh-pages/lints.json out/master cp util/gh-pages/style.css out/master if [[ -n $TAG_NAME ]]; then diff --git a/.gitignore b/.gitignore index 181b71a658b9a..a7c25b29021fb 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ out # gh pages docs util/gh-pages/lints.json +util/gh-pages/index.html # rustfmt backups *.rs.bk diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d253d52531e6..4bdbc91db9397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,46 @@ document. ## Unreleased / Beta / In Rust Nightly -[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master) +[0f8eabd6...master](https://github.com/rust-lang/rust-clippy/compare/0f8eabd6...master) + +## Rust 1.82 + +Current stable, released 2024-10-17 + +[View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-07-11T20%3A12%3A07Z..2024-08-24T20%3A55%3A35Z+base%3Amaster) + +### New Lints + +* Added [`too_long_first_doc_paragraph`] to `nursery` + [#12993](https://github.com/rust-lang/rust-clippy/pull/12993) +* Added [`unused_result_ok`] to `restriction` + [#12150](https://github.com/rust-lang/rust-clippy/pull/12150) +* Added [`pathbuf_init_then_push`] to `restriction` + [#11700](https://github.com/rust-lang/rust-clippy/pull/11700) + +### Enhancements + +* [`explicit_iter_loop`]: Now respects the `msrv` configuration + [#13288](https://github.com/rust-lang/rust-clippy/pull/13288) +* [`assigning_clones`]: No longer lints in test code + [#13273](https://github.com/rust-lang/rust-clippy/pull/13273) +* [`inconsistent_struct_constructor`]: Lint attributes now work on the struct definition + [#13211](https://github.com/rust-lang/rust-clippy/pull/13211) +* [`set_contains_or_insert`]: Now also checks for `BTreeSet` + [#13053](https://github.com/rust-lang/rust-clippy/pull/13053) +* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]: AccessKit, + CoreFoundation, CoreGraphics, CoreText, Direct2D, Direct3D, DirectWrite, PostScript, + OpenAL, OpenType, WebRTC, WebSocket, WebTransport, NetBSD, and OpenBSD + [#13093](https://github.com/rust-lang/rust-clippy/pull/13093) + +### ICE Fixes + +* [`uninit_vec`] + [rust#128720](https://github.com/rust-lang/rust/pull/128720) ## Rust 1.81 -Current stable, released 2024-09-05 +Released 2024-09-05 ### New Lints @@ -5621,6 +5656,7 @@ Released 2018-09-13 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one +[`manual_ignore_case_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ignore_case_cmp [`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check @@ -5874,6 +5910,7 @@ Released 2018-09-13 [`ref_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns +[`regex_creation_in_loops`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_creation_in_loops [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once @@ -6027,6 +6064,7 @@ Released 2018-09-13 [`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations +[`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor [`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max diff --git a/Cargo.toml b/Cargo.toml index cf810798d8cc1..1f7784fc489f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.83" +version = "0.1.84" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -23,7 +23,7 @@ path = "src/driver.rs" [dependencies] clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } -rustc_tools_util = "0.3.0" +rustc_tools_util = "0.4.0" tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" @@ -39,6 +39,8 @@ toml = "0.7.3" walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" +pulldown-cmark = "0.11" +rinja = { version = "0.3", default-features = false, features = ["config"] } # UI test dependencies clippy_utils = { path = "clippy_utils" } @@ -50,7 +52,7 @@ parking_lot = "0.12" tokio = { version = "1", features = ["io-util"] } [build-dependencies] -rustc_tools_util = "0.3.0" +rustc_tools_util = "0.4.0" [features] integration = ["tempfile"] diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 07a56fb33df11..43b551ae21617 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -329,7 +329,7 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] ## `array-size-threshold` The maximum allowed size for arrays on the stack -**Default Value:** `512000` +**Default Value:** `16384` --- **Affected lints:** diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 9da7112345de9..d21df202dcaba 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.83" +version = "0.1.84" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index e4e2c97fdc1d9..4757c0b1339a7 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -97,6 +97,30 @@ impl ConfError { } } +// Remove code tags and code behind '# 's, as they are not needed for the lint docs and --explain +pub fn sanitize_explanation(raw_docs: &str) -> String { + // Remove tags and hidden code: + let mut explanation = String::with_capacity(128); + let mut in_code = false; + for line in raw_docs.lines().map(str::trim) { + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { + explanation += line; + explanation.push('\n'); + } + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + explanation += line; + explanation.push('\n'); + } + } + + explanation +} + macro_rules! wrap_option { () => { None @@ -366,7 +390,7 @@ define_Conf! { arithmetic_side_effects_allowed_unary: Vec = <_>::default(), /// The maximum allowed size for arrays on the stack #[lints(large_const_arrays, large_stack_arrays)] - array_size_threshold: u64 = 512_000, + array_size_threshold: u64 = 16 * 1024, /// Suppress lints whenever the suggested change would cause breakage for other crates. #[lints( box_collection, diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index c63d98a0a13f9..42651521f8d7a 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -26,5 +26,5 @@ mod metadata; pub mod msrvs; pub mod types; -pub use conf::{Conf, get_configuration_metadata, lookup_conf_file}; +pub use conf::{Conf, get_configuration_metadata, lookup_conf_file, sanitize_explanation}; pub use metadata::ClippyConfiguration; diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 68a3b11d3848f..2f4da4cba3df3 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,8 +17,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,83,0 { CONST_EXTERN_FN } - 1,83,0 { CONST_FLOAT_BITS_CONV } + 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY } 1,82,0 { IS_NONE_OR } 1,81,0 { LINT_REASONS_STABILIZATION } 1,80,0 { BOX_INTO_ITER} diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index a5d72c3a559df..952a8711fb4e4 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -9,7 +9,7 @@ aho-corasick = "1.0" clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" -opener = "0.6" +opener = "0.7" shell-escape = "0.1" walkdir = "2.3" diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 5fd65017cfb97..e15ba3397178a 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -207,13 +207,13 @@ pub(crate) fn get_stabilization_version() -> String { fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { let mut test = formatdoc!( - r#" + r" #![warn(clippy::{lint_name})] fn main() {{ // test code goes here }} - "# + " ); if msrv { @@ -272,23 +272,23 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( - r#" + r" use clippy_config::msrvs::{{self, Msrv}}; use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; - "# + " ) } else { formatdoc!( - r#" + r" {pass_import} use rustc_lint::{{{context_import}, {pass_type}}}; use rustc_session::declare_lint_pass; - "# + " ) }); @@ -296,7 +296,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( - r#" + r" pub struct {name_camel} {{ msrv: Msrv, }} @@ -315,15 +315,15 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { // TODO: Add MSRV level to `clippy_config/src/msrvs.rs` if needed. // TODO: Update msrv config comment in `clippy_config/src/conf.rs` - "# + " ) } else { formatdoc!( - r#" + r" declare_lint_pass!({name_camel} => [{name_upper}]); impl {pass_type}{pass_lifetimes} for {name_camel} {{}} - "# + " ) }); @@ -416,7 +416,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R } else { let _: fmt::Result = writedoc!( lint_file_contents, - r#" + r" use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; @@ -425,7 +425,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R pub(super) fn check(cx: &{context_import}{pass_lifetimes}) {{ todo!(); }} - "# + " ); } diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index cc14cd8dae69e..d367fefec619c 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -19,7 +19,9 @@ pub fn run(port: u16, lint: Option) -> ! { }); loop { - if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") { + let index_time = mtime("util/gh-pages/index.html"); + + if index_time < mtime("clippy_lints/src") || index_time < mtime("util/gh-pages/index_template.html") { Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("collect-metadata") .spawn() diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d1188940b46a8..63ea6faf60dbd 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.83" +version = "0.1.84" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -13,7 +13,6 @@ arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } -declare_clippy_lint = { path = "../declare_clippy_lint" } itertools = "0.12" quine-mc_cluskey = "0.2" regex-syntax = "0.8" diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 40d154c0bdfe3..bf1d077fec28f 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -47,7 +47,7 @@ impl LateLintPass<'_> for BoxDefault { // And the call is that of a `Box` method && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) // And the single argument to the call is another function call - // This is the `T::default()` of `Box::new(T::default())` + // This is the `T::default()` (or default equivalent) of `Box::new(T::default())` && let ExprKind::Call(arg_path, _) = arg.kind // And we are not in a foreign crate's macro && !in_external_macro(cx.sess(), expr.span) diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs index dd2620b0b9df9..d88c0711b3971 100644 --- a/clippy_lints/src/byte_char_slices.rs +++ b/clippy_lints/src/byte_char_slices.rs @@ -41,7 +41,7 @@ impl EarlyLintPass for ByteCharSlice { "can be more succinctly written as a byte str", "try", format!("b\"{slice}\""), - Applicability::MaybeIncorrect, + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index d4d5ee37bccbb..b7b63250864e6 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -19,7 +19,7 @@ pub(super) fn check( if msrv.meets(msrvs::UNSIGNED_ABS) && let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() - && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind + && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind && method_path.ident.name.as_str() == "abs" { let span = if from.bit_width() == to.bit_width() { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 960c81045e36f..b11b967f8bc78 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind { + } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind { if method_path.ident.name == sym!(cast) && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 24570d8f4401c..b43906903a0e0 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Call(func, [arg, ..]) = expr.kind + if let ExprKind::Call(func, [arg]) = expr.kind && let ExprKind::Path(ref path) = func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id) diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs new file mode 100644 index 0000000000000..b1e39c70baa2b --- /dev/null +++ b/clippy_lints/src/declare_clippy_lint.rs @@ -0,0 +1,162 @@ +#[macro_export] +#[allow(clippy::crate_in_macro_def)] +macro_rules! declare_clippy_lint { + (@ + $(#[doc = $lit:literal])* + pub $lint_name:ident, + $category:ident, + $lintcategory:expr, + $desc:literal, + $version_expr:expr, + $version_lit:literal + ) => { + rustc_session::declare_tool_lint! { + $(#[doc = $lit])* + #[clippy::version = $version_lit] + pub clippy::$lint_name, + $category, + $desc, + report_in_external_macro:true + } + + pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { + lint: &$lint_name, + category: $lintcategory, + explanation: concat!($($lit,"\n",)*), + location: concat!(file!(), "#L", line!()), + version: $version_expr + }; + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + restriction, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + style, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Style, $desc, + Some($version), $version + + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + correctness, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, + Some($version), $version + + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + perf, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Perf, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + complexity, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + suspicious, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + nursery, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + pedantic, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + cargo, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, + Some($version), $version + } + }; + + ( + $(#[doc = $lit:literal])* + pub $lint_name:ident, + internal, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Internal, $desc, + None, "0.0.0" + } + }; +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 9cec672beb004..3c4e75df8abe4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -306,6 +306,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, + crate::manual_ignore_case_cmp::MANUAL_IGNORE_CASE_CMP_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, @@ -639,6 +640,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, + crate::regex::REGEX_CREATION_IN_LOOPS_INFO, crate::regex::TRIVIAL_REGEX_INFO, crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO, crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO, @@ -736,6 +738,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unit_types::UNIT_CMP_INFO, crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO, crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO, + crate::unnecessary_literal_bound::UNNECESSARY_LITERAL_BOUND_INFO, crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index dc10b64698b4f..de775b647952e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if !expr.span.from_expansion() // Avoid cases already linted by `field_reassign_with_default` && !self.reassigned_linted.contains(&expr.span) - && let ExprKind::Call(path, ..) = expr.kind + && let ExprKind::Call(path, []) = expr.kind && !in_automatically_derived(cx.tcx, expr.hir_id) && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() @@ -253,7 +253,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { /// Checks if the given expression is the `default` method belonging to the `Default` trait. fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { - if let ExprKind::Call(fn_expr, _) = &expr.kind + if let ExprKind::Call(fn_expr, []) = &expr.kind && let ExprKind::Path(qpath) = &fn_expr.kind && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) { diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index e090644ae4410..89c6a4e08dc44 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -452,7 +452,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.82.0"] pub TOO_LONG_FIRST_DOC_PARAGRAPH, - style, + nursery, "ensure that the first line of a documentation paragraph isn't too long" } diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index f37d11f7eb9b7..3c235fab0098b 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -43,7 +43,7 @@ declare_lint_pass!(Exit => [EXIT]); impl<'tcx> LateLintPass<'tcx> for Exit { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Call(path_expr, _args) = e.kind + if let ExprKind::Call(path_expr, [_]) = e.kind && let ExprKind::Path(ref path) = path_expr.kind && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::process_exit, def_id) diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 5b423a96918f6..4e4434ec7d19c 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) - && let ExprKind::Call(write_recv_path, _) = write_recv.kind + && let ExprKind::Call(write_recv_path, []) = write_recv.kind && write_fun.ident.name == sym!(write_fmt) && let Some(def_id) = path_def_id(cx, write_recv_path) { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 8da6623f34de9..daa199779e3cb 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -436,12 +436,12 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { lhs, rhs, ) = expr.kind + && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind + && path.ident.name.as_str() == "exp" && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) && (F32(1.0) == value || F64(1.0) == value) - && let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind && cx.typeck_results().expr_ty(self_arg).is_floating_point() - && path.ident.name.as_str() == "exp" { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 7c0515b8c5608..5619cb0ab1b06 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -151,7 +151,7 @@ struct FormatImplExpr<'a, 'tcx> { impl FormatImplExpr<'_, '_> { fn check_to_string_in_display(&self) { if self.format_trait_impl.name == sym::Display - && let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind + && let ExprKind::MethodCall(path, self_arg, [], _) = self.expr.kind // Get the hir_id of the object we are calling the method on // Is the method to_string() ? && path.ident.name == sym::to_string diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 1c52514a330d4..ba80c099a0153 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -82,7 +82,7 @@ fn mutex_lock_call<'tcx>( expr: &'tcx Expr<'_>, op_mutex: Option<&'tcx Expr<'_>>, ) -> ControlFlow<&'tcx Expr<'tcx>> { - if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind + if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind && path.ident.as_str() == "lock" && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() && is_type_diagnostic_item(cx, ty, sym::Mutex) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index f4a64f5c20b44..3b84b569c3edf 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -139,6 +139,13 @@ fn check_manual_check<'tcx>( if_block, else_block, msrv, + matches!( + clippy_utils::get_parent_expr(cx, expr), + Some(Expr { + kind: ExprKind::If(..), + .. + }) + ), ), BinOpKind::Lt | BinOpKind::Le => check_gt( cx, @@ -149,6 +156,13 @@ fn check_manual_check<'tcx>( if_block, else_block, msrv, + matches!( + clippy_utils::get_parent_expr(cx, expr), + Some(Expr { + kind: ExprKind::If(..), + .. + }) + ), ), _ => {}, } @@ -165,6 +179,7 @@ fn check_gt( if_block: &Expr<'_>, else_block: &Expr<'_>, msrv: &Msrv, + is_composited: bool, ) { if let Some(big_var) = Var::new(big_var) && let Some(little_var) = Var::new(little_var) @@ -178,6 +193,7 @@ fn check_gt( if_block, else_block, msrv, + is_composited, ); } } @@ -206,6 +222,7 @@ fn check_subtraction( if_block: &Expr<'_>, else_block: &Expr<'_>, msrv: &Msrv, + is_composited: bool, ) { let if_block = peel_blocks(if_block); let else_block = peel_blocks(else_block); @@ -226,6 +243,7 @@ fn check_subtraction( else_block, if_block, msrv, + is_composited, ); return; } @@ -242,13 +260,18 @@ fn check_subtraction( && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) && (!is_in_const_context(cx) || msrv.meets(msrvs::SATURATING_SUB_CONST)) { + let sugg = format!( + "{}{big_var_snippet}.saturating_sub({little_var_snippet}){}", + if is_composited { "{ " } else { "" }, + if is_composited { " }" } else { "" } + ); span_lint_and_sugg( cx, IMPLICIT_SATURATING_SUB, expr_span, "manual arithmetic check found", "replace it with", - format!("{big_var_snippet}.saturating_sub({little_var_snippet})"), + sugg, Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 590d9afd1b437..f4c00d8287def 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,8 +3,8 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, - TyKind, WherePredicate, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, + WherePredicate, }; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 66a8a3167a4f2..dd90e2a6e94f4 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -50,11 +50,28 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Detects type names that are prefixed or suffixed by the - /// containing module's name. + /// Detects public item names that are prefixed or suffixed by the + /// containing public module's name. /// /// ### Why is this bad? - /// It requires the user to type the module name twice. + /// It requires the user to type the module name twice in each usage, + /// especially if they choose to import the module rather than its contents. + /// + /// Lack of such repetition is also the style used in the Rust standard library; + /// e.g. `io::Error` and `fmt::Error` rather than `io::IoError` and `fmt::FmtError`; + /// and `array::from_ref` rather than `array::array_from_ref`. + /// + /// ### Known issues + /// Glob re-exports are ignored; e.g. this will not warn even though it should: + /// + /// ```no_run + /// pub mod foo { + /// mod iteration { + /// pub struct FooIter {} + /// } + /// pub use iteration::*; // creates the path `foo::FooIter` + /// } + /// ``` /// /// ### Example /// ```no_run @@ -71,7 +88,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.33.0"] pub MODULE_NAME_REPETITIONS, - pedantic, + restriction, "type names prefixed/postfixed with their containing module's name" } @@ -389,12 +406,12 @@ impl LateLintPass<'_> for ItemNameRepetitions { let item_name = item.ident.name.as_str(); let item_camel = to_camel_case(item_name); if !item.span.from_expansion() && is_present_in_source(cx, item.span) { - if let [.., (mod_name, mod_camel, owner_id)] = &*self.modules { + if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules { // constants don't have surrounding modules if !mod_camel.is_empty() { if mod_name == &item.ident.name && let ItemKind::Mod(..) = item.kind - && (!self.allow_private_module_inception || cx.tcx.visibility(owner_id.def_id).is_public()) + && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public()) { span_lint( cx, @@ -403,9 +420,13 @@ impl LateLintPass<'_> for ItemNameRepetitions { "module has the same name as its containing module", ); } + // The `module_name_repetitions` lint should only trigger if the item has the module in its // name. Having the same name is accepted. - if cx.tcx.visibility(item.owner_id).is_public() && item_camel.len() > mod_camel.len() { + if cx.tcx.visibility(item.owner_id).is_public() + && cx.tcx.visibility(mod_owner_id.def_id).is_public() + && item_camel.len() > mod_camel.len() + { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 6f5065e4936cb..25f9be8b2d7a4 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -57,7 +57,7 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); impl<'tcx> LateLintPass<'tcx> for LargeFuture { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind - && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind + && let ExprKind::Call(func, [arg]) = scrutinee.kind && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind && !expr.span.from_expansion() && let ty = cx.typeck_results().expr_ty(arg) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 0f061d6de504f..4ef881f11d599 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,3 +1,5 @@ +use std::num::Saturating; + use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; @@ -30,6 +32,7 @@ declare_clippy_lint! { pub struct LargeStackArrays { maximum_allowed_size: u64, prev_vec_macro_callsite: Option, + const_item_counter: Saturating, } impl LargeStackArrays { @@ -37,6 +40,7 @@ impl LargeStackArrays { Self { maximum_allowed_size: conf.array_size_threshold, prev_vec_macro_callsite: None, + const_item_counter: Saturating(0), } } @@ -60,8 +64,21 @@ impl LargeStackArrays { impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { + fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if matches!(item.kind, ItemKind::Static(..) | ItemKind::Const(..)) { + self.const_item_counter += 1; + } + } + + fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if matches!(item.kind, ItemKind::Static(..) | ItemKind::Const(..)) { + self.const_item_counter -= 1; + } + } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind + if self.const_item_counter.0 == 0 + && let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 035ee40348c77..47c65ee6d0ba9 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -513,7 +513,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> return; } - if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -521,29 +521,17 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len( - cx, - span, - method_path.ident.name, - receiver, - args, - &lit.node, - op, - compare_to, - ); + check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } } -// FIXME(flip1995): Figure out how to reduce the number of arguments -#[allow(clippy::too_many_arguments)] fn check_len( cx: &LateContext<'_>, span: Span, method_name: Symbol, receiver: &Expr<'_>, - args: &[Expr<'_>], lit: &LitKind, op: &str, compare_to: u32, @@ -554,7 +542,7 @@ fn check_len( return; } - if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) { + if method_name == sym::len && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6ee064a6124b9..6e29dde2211fb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,6 +1,7 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] +#![feature(macro_metavar_expr_concat)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] @@ -56,9 +57,10 @@ extern crate rustc_trait_selection; extern crate thin_vec; #[macro_use] -extern crate clippy_utils; +mod declare_clippy_lint; + #[macro_use] -extern crate declare_clippy_lint; +extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; @@ -203,6 +205,7 @@ mod manual_clamp; mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; +mod manual_ignore_case_cmp; mod manual_is_ascii_check; mod manual_is_power_of_two; mod manual_let_else; @@ -360,6 +363,7 @@ mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; mod unnecessary_box_returns; +mod unnecessary_literal_bound; mod unnecessary_map_on_constructor; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; @@ -391,7 +395,7 @@ mod zero_sized_map_values; mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` -use clippy_config::{Conf, get_configuration_metadata}; +use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -519,8 +523,9 @@ impl LintInfo { pub fn explain(name: &str) -> i32 { let target = format!("clippy::{}", name.to_ascii_uppercase()); + if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - println!("{}", info.explanation); + println!("{}", sanitize_explanation(info.explanation)); // Check if the lint has configuration let mut mdconf = get_configuration_metadata(); let name = name.to_ascii_lowercase(); @@ -896,7 +901,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); store.register_early_pass(|| Box::new(visibility::Visibility)); store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions::new(conf))); - store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods)); + store.register_late_pass(move |_| Box::new(manual_float_methods::ManualFloatMethods::new(conf))); store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes)); store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError)); store.register_late_pass(move |_| Box::new(absolute_paths::AbsolutePaths::new(conf))); @@ -941,5 +946,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); + store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)); + store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index a7c48eb216aa4..5a3930b8bb846 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, + Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref, + walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 81f2a03fb55fb..e2dcb20f906d3 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -412,7 +412,6 @@ impl LiteralDigitGrouping { } } -#[expect(clippy::module_name_repetitions)] pub struct DecimalLiteralRepresentation { threshold: u64, } diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 858e3be5093ef..e25c03db53442 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -42,6 +42,7 @@ pub(super) fn check<'tcx>( let mut loop_visitor = LoopVisitor { cx, label, + inner_labels: label.into_iter().collect(), is_finite: false, loop_depth: 0, }; @@ -93,6 +94,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option struct LoopVisitor<'hir, 'tcx> { cx: &'hir LateContext<'tcx>, label: Option(), 0); - let _a: A = std::ptr::read(core::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::read(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); + let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); - let _a: A = std::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); + let _a: A = std::ptr::replace(std::ptr::NonNull::dangling().as_ptr(), A); let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); - std::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); - std::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); + std::ptr::swap::(std::ptr::NonNull::dangling().as_ptr(), &mut A); + std::ptr::swap::(&mut A, std::ptr::NonNull::dangling().as_ptr()); - std::ptr::swap_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), &mut A, 0); - std::ptr::swap_nonoverlapping::(&mut A, core::ptr::NonNull::dangling().as_ptr(), 0); + std::ptr::swap_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), &mut A, 0); + std::ptr::swap_nonoverlapping::(&mut A, std::ptr::NonNull::dangling().as_ptr(), 0); - std::ptr::write(core::ptr::NonNull::dangling().as_ptr(), A); + std::ptr::write(std::ptr::NonNull::dangling().as_ptr(), A); - std::ptr::write_unaligned(core::ptr::NonNull::dangling().as_ptr(), A); + std::ptr::write_unaligned(std::ptr::NonNull::dangling().as_ptr(), A); - std::ptr::write_volatile(core::ptr::NonNull::dangling().as_ptr(), A); + std::ptr::write_volatile(std::ptr::NonNull::dangling().as_ptr(), A); - std::ptr::write_bytes::(core::ptr::NonNull::dangling().as_ptr(), 42, 0); + std::ptr::write_bytes::(std::ptr::NonNull::dangling().as_ptr(), 42, 0); } } diff --git a/tests/ui/invalid_null_ptr_usage.stderr b/tests/ui/invalid_null_ptr_usage.stderr index a0be2c0ad75c6..613a2cc36885c 100644 --- a/tests/ui/invalid_null_ptr_usage.stderr +++ b/tests/ui/invalid_null_ptr_usage.stderr @@ -2,7 +2,7 @@ error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:3:59 | LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` | = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default @@ -10,127 +10,127 @@ error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:4:59 | LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:6:63 | LL | let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:8:33 | LL | std::ptr::copy::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:9:73 | LL | std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:11:48 | LL | std::ptr::copy_nonoverlapping::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:12:88 | LL | std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:17:36 | LL | let _a: A = std::ptr::read(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:18:36 | LL | let _a: A = std::ptr::read(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:20:46 | LL | let _a: A = std::ptr::read_unaligned(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:21:46 | LL | let _a: A = std::ptr::read_unaligned(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:23:45 | LL | let _a: A = std::ptr::read_volatile(std::ptr::null()); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:24:45 | LL | let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:26:39 | LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:30:29 | LL | std::ptr::swap::(std::ptr::null_mut(), &mut A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:31:37 | LL | std::ptr::swap::(&mut A, std::ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:33:44 | LL | std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:34:52 | LL | std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:36:25 | LL | std::ptr::write(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:38:35 | LL | std::ptr::write_unaligned(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:40:34 | LL | std::ptr::write_volatile(std::ptr::null_mut(), A); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null --> tests/ui/invalid_null_ptr_usage.rs:42:40 | LL | std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: aborting due to 22 previous errors diff --git a/tests/ui/invalid_null_ptr_usage_no_std.fixed b/tests/ui/invalid_null_ptr_usage_no_std.fixed new file mode 100644 index 0000000000000..2bbfe72742426 --- /dev/null +++ b/tests/ui/invalid_null_ptr_usage_no_std.fixed @@ -0,0 +1,57 @@ +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn main() { + unsafe { + let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); + let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); + + let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0); + + core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + + core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + + struct A; // zero sized struct + assert_eq!(core::mem::size_of::(), 0); + + let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); + + let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); + + let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); + let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); + + let _a: A = core::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); + let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint + let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); + + core::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); + core::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); + + core::ptr::swap_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), &mut A, 0); + core::ptr::swap_nonoverlapping::(&mut A, core::ptr::NonNull::dangling().as_ptr(), 0); + + core::ptr::write(core::ptr::NonNull::dangling().as_ptr(), A); + + core::ptr::write_unaligned(core::ptr::NonNull::dangling().as_ptr(), A); + + core::ptr::write_volatile(core::ptr::NonNull::dangling().as_ptr(), A); + + core::ptr::write_bytes::(core::ptr::NonNull::dangling().as_ptr(), 42, 0); + } +} diff --git a/tests/ui/invalid_null_ptr_usage_no_std.rs b/tests/ui/invalid_null_ptr_usage_no_std.rs new file mode 100644 index 0000000000000..cbce44f7c0d9b --- /dev/null +++ b/tests/ui/invalid_null_ptr_usage_no_std.rs @@ -0,0 +1,57 @@ +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn main() { + unsafe { + let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null(), 0); + let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); + + let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); + + core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + + core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + + struct A; // zero sized struct + assert_eq!(core::mem::size_of::(), 0); + + let _a: A = core::ptr::read(core::ptr::null()); + let _a: A = core::ptr::read(core::ptr::null_mut()); + + let _a: A = core::ptr::read_unaligned(core::ptr::null()); + let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); + + let _a: A = core::ptr::read_volatile(core::ptr::null()); + let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); + + let _a: A = core::ptr::replace(core::ptr::null_mut(), A); + let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint + let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); + + core::ptr::swap::(core::ptr::null_mut(), &mut A); + core::ptr::swap::(&mut A, core::ptr::null_mut()); + + core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); + core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); + + core::ptr::write(core::ptr::null_mut(), A); + + core::ptr::write_unaligned(core::ptr::null_mut(), A); + + core::ptr::write_volatile(core::ptr::null_mut(), A); + + core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); + } +} diff --git a/tests/ui/invalid_null_ptr_usage_no_std.stderr b/tests/ui/invalid_null_ptr_usage_no_std.stderr new file mode 100644 index 0000000000000..df0d40e9e072c --- /dev/null +++ b/tests/ui/invalid_null_ptr_usage_no_std.stderr @@ -0,0 +1,136 @@ +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:16:60 + | +LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null(), 0); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + | + = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:17:60 + | +LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:19:64 + | +LL | let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:21:34 + | +LL | core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:22:75 + | +LL | core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:24:49 + | +LL | core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:25:90 + | +LL | core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:30:37 + | +LL | let _a: A = core::ptr::read(core::ptr::null()); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:31:37 + | +LL | let _a: A = core::ptr::read(core::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:33:47 + | +LL | let _a: A = core::ptr::read_unaligned(core::ptr::null()); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:34:47 + | +LL | let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:36:46 + | +LL | let _a: A = core::ptr::read_volatile(core::ptr::null()); + | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:37:46 + | +LL | let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:39:40 + | +LL | let _a: A = core::ptr::replace(core::ptr::null_mut(), A); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:43:30 + | +LL | core::ptr::swap::(core::ptr::null_mut(), &mut A); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:44:38 + | +LL | core::ptr::swap::(&mut A, core::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:46:45 + | +LL | core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:47:53 + | +LL | core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:49:26 + | +LL | core::ptr::write(core::ptr::null_mut(), A); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:51:36 + | +LL | core::ptr::write_unaligned(core::ptr::null_mut(), A); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:53:35 + | +LL | core::ptr::write_volatile(core::ptr::null_mut(), A); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: pointer must be non-null + --> tests/ui/invalid_null_ptr_usage_no_std.rs:55:41 + | +LL | core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/large_const_arrays.fixed b/tests/ui/large_const_arrays.fixed index 6011bb99dec25..543ce460e7ba7 100644 --- a/tests/ui/large_const_arrays.fixed +++ b/tests/ui/large_const_arrays.fixed @@ -12,9 +12,9 @@ pub static FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; static FOO: [u32; 1_000_000] = [0u32; 1_000_000]; // Good -pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000]; -pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000]; -const G_FOO: [u32; 1_000] = [0u32; 1_000]; +pub(crate) const G_FOO_PUB_CRATE: [u32; 250] = [0u32; 250]; +pub const G_FOO_PUB: [u32; 250] = [0u32; 250]; +const G_FOO: [u32; 250] = [0u32; 250]; fn main() { // Should lint @@ -26,10 +26,10 @@ fn main() { static BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; // Good - pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000]; - const G_BAR: [u32; 1_000] = [0u32; 1_000]; - pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500]; - const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500]; - pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200]; - const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200]; + pub const G_BAR_PUB: [u32; 250] = [0u32; 250]; + const G_BAR: [u32; 250] = [0u32; 250]; + pub const G_BAR_STRUCT_PUB: [S; 4] = [S { data: [0; 32] }; 4]; + const G_BAR_STRUCT: [S; 4] = [S { data: [0; 32] }; 4]; + pub const G_BAR_S_PUB: [Option<&str>; 50] = [Some("str"); 50]; + const G_BAR_S: [Option<&str>; 50] = [Some("str"); 50]; } diff --git a/tests/ui/large_const_arrays.rs b/tests/ui/large_const_arrays.rs index a78425d7bc627..e23a8081171d6 100644 --- a/tests/ui/large_const_arrays.rs +++ b/tests/ui/large_const_arrays.rs @@ -12,9 +12,9 @@ pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; // Good -pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000]; -pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000]; -const G_FOO: [u32; 1_000] = [0u32; 1_000]; +pub(crate) const G_FOO_PUB_CRATE: [u32; 250] = [0u32; 250]; +pub const G_FOO_PUB: [u32; 250] = [0u32; 250]; +const G_FOO: [u32; 250] = [0u32; 250]; fn main() { // Should lint @@ -26,10 +26,10 @@ fn main() { const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; // Good - pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000]; - const G_BAR: [u32; 1_000] = [0u32; 1_000]; - pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500]; - const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500]; - pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200]; - const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200]; + pub const G_BAR_PUB: [u32; 250] = [0u32; 250]; + const G_BAR: [u32; 250] = [0u32; 250]; + pub const G_BAR_STRUCT_PUB: [S; 4] = [S { data: [0; 32] }; 4]; + const G_BAR_STRUCT: [S; 4] = [S { data: [0; 32] }; 4]; + pub const G_BAR_S_PUB: [Option<&str>; 50] = [Some("str"); 50]; + const G_BAR_S: [Option<&str>; 50] = [Some("str"); 50]; } diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs index 6bcaf481c9f7e..cd72b9bfa479a 100644 --- a/tests/ui/large_stack_arrays.rs +++ b/tests/ui/large_stack_arrays.rs @@ -15,6 +15,12 @@ enum E { T(u32), } +const STATIC_PROMOTED_LARGE_ARRAY: &[u8; 512001] = &[0; 512001]; +const STATIC_PROMOTED_LARGE_ARRAY_WITH_NESTED: &[u8; 512001] = { + const NESTED: () = (); + &[0; 512001] +}; + pub static DOESNOTLINT: [u8; 512_001] = [0; 512_001]; pub static DOESNOTLINT2: [u8; 512_001] = { let x = 0; @@ -23,38 +29,38 @@ pub static DOESNOTLINT2: [u8; 512_001] = { fn issue_10741() { #[derive(Copy, Clone)] - struct Large([u32; 100_000]); + struct Large([u32; 2048]); fn build() -> Large { - Large([0; 100_000]) + Large([0; 2048]) } let _x = [build(); 3]; - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes let _y = [build(), build(), build()]; - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes } fn main() { let bad = ( [0u32; 20_000_000], - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes [S { data: [0; 32] }; 5000], - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes [Some(""); 20_000_000], - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes [E::T(0); 5000], - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes [0u8; usize::MAX], - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes ); let good = ( - [0u32; 1000], - [S { data: [0; 32] }; 1000], - [Some(""); 1000], - [E::T(0); 1000], + [0u32; 50], + [S { data: [0; 32] }; 4], + [Some(""); 50], + [E::T(0); 2], [(); 20_000_000], ); } @@ -68,7 +74,7 @@ fn issue_12586() { // Weird rule to test help messages. ($a:expr => $b:expr) => { [$a, $b, $a, $b] - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes }; ($id:ident; $n:literal) => { dummy!(::std::vec![$id;$n]) @@ -80,26 +86,26 @@ fn issue_12586() { macro_rules! create_then_move { ($id:ident; $n:literal) => {{ let _x_ = [$id; $n]; - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes _x_ }}; } - let x = [0u32; 50_000]; + let x = [0u32; 4096]; let y = vec![x, x, x, x, x]; let y = vec![dummy![x, x, x, x, x]]; let y = vec![dummy![[x, x, x, x, x]]]; let y = dummy![x, x, x, x, x]; let y = [x, x, dummy!(x), x, x]; - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes let y = dummy![x => x]; let y = dummy![x;5]; let y = dummy!(vec![dummy![x, x, x, x, x]]); let y = dummy![[x, x, x, x, x]]; - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes let y = proc_macros::make_it_big!([x; 1]); - //~^ ERROR: allocating a local array larger than 512000 bytes + //~^ ERROR: allocating a local array larger than 16384 bytes let y = vec![proc_macros::make_it_big!([x; 10])]; let y = vec![create_then_move![x; 5]; 5]; } diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index 06294ee8b8cb1..f48706415e66a 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -1,5 +1,5 @@ -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:32:14 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:38:14 | LL | let _x = [build(); 3]; | ^^^^^^^^^^^^ @@ -8,64 +8,64 @@ LL | let _x = [build(); 3]; = note: `-D clippy::large-stack-arrays` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:35:14 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:41:14 | LL | let _y = [build(), build(), build()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![build(), build(), build()].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:41:9 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:47:9 | LL | [0u32; 20_000_000], | ^^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:43:9 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:49:9 | LL | [S { data: [0; 32] }; 5000], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:45:9 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:51:9 | LL | [Some(""); 20_000_000], | ^^^^^^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:47:9 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:53:9 | LL | [E::T(0); 5000], | ^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:49:9 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:55:9 | LL | [0u8; usize::MAX], | ^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:93:13 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:99:13 | LL | let y = [x, x, dummy!(x), x, x]; | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:70:13 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:76:13 | LL | [$a, $b, $a, $b] | ^^^^^^^^^^^^^^^^ @@ -75,22 +75,22 @@ LL | let y = dummy![x => x]; | = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info) -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:98:20 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:104:20 | LL | let y = dummy![[x, x, x, x, x]]; | ^^^^^^^^^^^^^^^ | = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:101:39 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:107:39 | LL | let y = proc_macros::make_it_big!([x; 1]); | ^^^^^^ -error: allocating a local array larger than 512000 bytes - --> tests/ui/large_stack_arrays.rs:82:23 +error: allocating a local array larger than 16384 bytes + --> tests/ui/large_stack_arrays.rs:88:23 | LL | let _x_ = [$id; $n]; | ^^^^^^^^^ diff --git a/tests/ui/manual_c_str_literals.fixed b/tests/ui/manual_c_str_literals.edition2021.fixed similarity index 93% rename from tests/ui/manual_c_str_literals.fixed rename to tests/ui/manual_c_str_literals.edition2021.fixed index a24d7088c882a..391c63bb4b89c 100644 --- a/tests/ui/manual_c_str_literals.fixed +++ b/tests/ui/manual_c_str_literals.edition2021.fixed @@ -1,3 +1,6 @@ +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 #![warn(clippy::manual_c_str_literals)] #![allow(clippy::no_effect)] diff --git a/tests/ui/manual_c_str_literals.stderr b/tests/ui/manual_c_str_literals.edition2021.stderr similarity index 84% rename from tests/ui/manual_c_str_literals.stderr rename to tests/ui/manual_c_str_literals.edition2021.stderr index 9c70bddb81c18..beab29ccdda02 100644 --- a/tests/ui/manual_c_str_literals.stderr +++ b/tests/ui/manual_c_str_literals.edition2021.stderr @@ -1,5 +1,5 @@ error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:31:5 + --> tests/ui/manual_c_str_literals.rs:34:5 | LL | CStr::from_bytes_with_nul(b"foo\0"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` @@ -8,73 +8,73 @@ LL | CStr::from_bytes_with_nul(b"foo\0"); = help: to override `-D warnings` add `#[allow(clippy::manual_c_str_literals)]` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:35:5 + --> tests/ui/manual_c_str_literals.rs:38:5 | LL | CStr::from_bytes_with_nul(b"foo\0"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:36:5 + --> tests/ui/manual_c_str_literals.rs:39:5 | LL | CStr::from_bytes_with_nul(b"foo\x00"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:37:5 + --> tests/ui/manual_c_str_literals.rs:40:5 | LL | CStr::from_bytes_with_nul(b"foo\0").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:38:5 + --> tests/ui/manual_c_str_literals.rs:41:5 | LL | CStr::from_bytes_with_nul(b"foo\\0sdsd\0").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo\\0sdsd"` error: calling `CStr::from_ptr` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:43:14 + --> tests/ui/manual_c_str_literals.rs:46:14 | LL | unsafe { CStr::from_ptr(b"foo\0".as_ptr().cast()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::from_ptr` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:44:14 + --> tests/ui/manual_c_str_literals.rs:47:14 | LL | unsafe { CStr::from_ptr(b"foo\0".as_ptr() as *const _) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:45:23 + --> tests/ui/manual_c_str_literals.rs:48:23 | LL | let _: *const _ = b"foo\0".as_ptr(); | ^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:46:23 + --> tests/ui/manual_c_str_literals.rs:49:23 | LL | let _: *const _ = "foo\0".as_ptr(); | ^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:49:23 + --> tests/ui/manual_c_str_literals.rs:52:23 | LL | let _: *const _ = b"foo\0".as_ptr().cast::(); | ^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:52:13 + --> tests/ui/manual_c_str_literals.rs:55:13 | LL | let _ = "电脑\\\0".as_ptr(); | ^^^^^^^^^^ help: use a `c""` literal: `c"电脑\\"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:53:13 + --> tests/ui/manual_c_str_literals.rs:56:13 | LL | let _ = "电脑\0".as_ptr(); | ^^^^^^^^ help: use a `c""` literal: `c"电脑"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:54:13 + --> tests/ui/manual_c_str_literals.rs:57:13 | LL | let _ = "电脑\x00".as_ptr(); | ^^^^^^^^^^ help: use a `c""` literal: `c"电脑"` diff --git a/tests/ui/manual_c_str_literals.rs b/tests/ui/manual_c_str_literals.rs index 0a007786720f7..39b622580774d 100644 --- a/tests/ui/manual_c_str_literals.rs +++ b/tests/ui/manual_c_str_literals.rs @@ -1,3 +1,6 @@ +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 #![warn(clippy::manual_c_str_literals)] #![allow(clippy::no_effect)] diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs index ee3daa12834b4..66545d180ef9e 100644 --- a/tests/ui/manual_float_methods.rs +++ b/tests/ui/manual_float_methods.rs @@ -39,8 +39,11 @@ fn main() { if x != f64::INFINITY && x != fn_test() {} // Not -inf if x != f64::INFINITY && x != fn_test_not_inf() {} + const { + let x = 1.0f64; + if x == f64::INFINITY || x == f64::NEG_INFINITY {} + } const X: f64 = 1.0f64; - // Will be linted if `const_float_classify` is enabled if const { X == f64::INFINITY || X == f64::NEG_INFINITY } {} if const { X != f64::INFINITY && X != f64::NEG_INFINITY } {} external! { diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr index 70057620a4a82..676a4485ab4dc 100644 --- a/tests/ui/manual_float_methods.stderr +++ b/tests/ui/manual_float_methods.stderr @@ -78,5 +78,11 @@ help: or, for conciseness LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ -error: aborting due to 6 previous errors +error: manually checking if a float is infinite + --> tests/ui/manual_float_methods.rs:44:12 + | +LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` + +error: aborting due to 7 previous errors diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed new file mode 100644 index 0000000000000..53a124f59c8dc --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -0,0 +1,107 @@ +#![allow(clippy::all)] +#![deny(clippy::manual_ignore_case_cmp)] + +use std::ffi::{OsStr, OsString}; + +fn main() {} + +fn variants(a: &str, b: &str) { + if a.eq_ignore_ascii_case(b) { + return; + } + if a.eq_ignore_ascii_case(b) { + return; + } + let r = a.eq_ignore_ascii_case(b); + let r = r || a.eq_ignore_ascii_case(b); + r && a.eq_ignore_ascii_case(&b.to_uppercase()); + // != + if !a.eq_ignore_ascii_case(b) { + return; + } + if !a.eq_ignore_ascii_case(b) { + return; + } + let r = !a.eq_ignore_ascii_case(b); + let r = r || !a.eq_ignore_ascii_case(b); + r && !a.eq_ignore_ascii_case(&b.to_uppercase()); +} + +fn unsupported(a: char, b: char) { + // TODO:: these are rare, and might not be worth supporting + a.to_ascii_lowercase() == char::to_ascii_lowercase(&b); + char::to_ascii_lowercase(&a) == b.to_ascii_lowercase(); + char::to_ascii_lowercase(&a) == char::to_ascii_lowercase(&b); +} + +fn char(a: char, b: char) { + a.eq_ignore_ascii_case(&b); + a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); + *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.eq_ignore_ascii_case(&'a'); + 'a'.eq_ignore_ascii_case(&b); +} +fn u8(a: u8, b: u8) { + a.eq_ignore_ascii_case(&b); + a.eq_ignore_ascii_case(&b'a'); + b'a'.eq_ignore_ascii_case(&b); +} +fn ref_str(a: &str, b: &str) { + a.eq_ignore_ascii_case(b); + a.to_uppercase().eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); +} +fn ref_ref_str(a: &&str, b: &&str) { + a.eq_ignore_ascii_case(b); + a.to_uppercase().eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); +} +fn string(a: String, b: String) { + a.eq_ignore_ascii_case(&b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&b); + &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); + &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&b); +} +fn ref_string(a: String, b: &String) { + a.eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); + + b.eq_ignore_ascii_case(&a); + b.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&a); +} +fn string_ref_str(a: String, b: &str) { + a.eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); + + b.eq_ignore_ascii_case(&a); + b.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&a); +} +fn ref_u8slice(a: &[u8], b: &[u8]) { + a.eq_ignore_ascii_case(b); +} +fn u8vec(a: Vec, b: Vec) { + a.eq_ignore_ascii_case(&b); +} +fn ref_u8vec(a: Vec, b: &Vec) { + a.eq_ignore_ascii_case(b); + b.eq_ignore_ascii_case(&a); +} +fn ref_osstr(a: &OsStr, b: &OsStr) { + a.eq_ignore_ascii_case(b); +} +fn osstring(a: OsString, b: OsString) { + a.eq_ignore_ascii_case(b); +} +fn ref_osstring(a: OsString, b: &OsString) { + a.eq_ignore_ascii_case(b); + b.eq_ignore_ascii_case(a); +} diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs new file mode 100644 index 0000000000000..2a4d84b30acec --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -0,0 +1,107 @@ +#![allow(clippy::all)] +#![deny(clippy::manual_ignore_case_cmp)] + +use std::ffi::{OsStr, OsString}; + +fn main() {} + +fn variants(a: &str, b: &str) { + if a.to_ascii_lowercase() == b.to_ascii_lowercase() { + return; + } + if a.to_ascii_uppercase() == b.to_ascii_uppercase() { + return; + } + let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); + let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); + r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); + // != + if a.to_ascii_lowercase() != b.to_ascii_lowercase() { + return; + } + if a.to_ascii_uppercase() != b.to_ascii_uppercase() { + return; + } + let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); + let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); + r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); +} + +fn unsupported(a: char, b: char) { + // TODO:: these are rare, and might not be worth supporting + a.to_ascii_lowercase() == char::to_ascii_lowercase(&b); + char::to_ascii_lowercase(&a) == b.to_ascii_lowercase(); + char::to_ascii_lowercase(&a) == char::to_ascii_lowercase(&b); +} + +fn char(a: char, b: char) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); + *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == 'a'; + 'a' == b.to_ascii_lowercase(); +} +fn u8(a: u8, b: u8) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == b'a'; + b'a' == b.to_ascii_lowercase(); +} +fn ref_str(a: &str, b: &str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn ref_ref_str(a: &&str, b: &&str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn string(a: String, b: String) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); + &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn ref_string(a: String, b: &String) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + + b.to_ascii_lowercase() == a.to_ascii_lowercase(); + b.to_ascii_lowercase() == "a"; + "a" == a.to_ascii_lowercase(); +} +fn string_ref_str(a: String, b: &str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + + b.to_ascii_lowercase() == a.to_ascii_lowercase(); + b.to_ascii_lowercase() == "a"; + "a" == a.to_ascii_lowercase(); +} +fn ref_u8slice(a: &[u8], b: &[u8]) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn u8vec(a: Vec, b: Vec) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn ref_u8vec(a: Vec, b: &Vec) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + b.to_ascii_lowercase() == a.to_ascii_lowercase(); +} +fn ref_osstr(a: &OsStr, b: &OsStr) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn osstring(a: OsString, b: OsString) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn ref_osstring(a: OsString, b: &OsString) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + b.to_ascii_lowercase() == a.to_ascii_lowercase(); +} diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr new file mode 100644 index 0000000000000..11e8b8aebb541 --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -0,0 +1,546 @@ +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:9:8 + | +LL | if a.to_ascii_lowercase() == b.to_ascii_lowercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/manual_ignore_case_cmp.rs:2:9 + | +LL | #![deny(clippy::manual_ignore_case_cmp)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:12:8 + | +LL | if a.to_ascii_uppercase() == b.to_ascii_uppercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:15:13 + | +LL | let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:16:18 + | +LL | let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = r || a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:17:10 + | +LL | r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | r && a.eq_ignore_ascii_case(&b.to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:19:8 + | +LL | if a.to_ascii_lowercase() != b.to_ascii_lowercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if !a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:22:8 + | +LL | if a.to_ascii_uppercase() != b.to_ascii_uppercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if !a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:25:13 + | +LL | let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = !a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:26:18 + | +LL | let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = r || !a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:27:10 + | +LL | r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | r && !a.eq_ignore_ascii_case(&b.to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:38:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:41:5 + | +LL | a.to_ascii_lowercase() == 'a'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&'a'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:42:5 + | +LL | 'a' == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | 'a'.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:45:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:46:5 + | +LL | a.to_ascii_lowercase() == b'a'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b'a'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:47:5 + | +LL | b'a' == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b'a'.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:50:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:51:5 + | +LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.to_uppercase().eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:52:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:53:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:56:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:57:5 + | +LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.to_uppercase().eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:58:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:59:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:62:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:63:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:64:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:67:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:68:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:71:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:72:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:73:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:75:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:76:5 + | +LL | b.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:77:5 + | +LL | "a" == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:80:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:81:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:82:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:84:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:85:5 + | +LL | b.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:86:5 + | +LL | "a" == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:89:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:92:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:95:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:96:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:99:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:102:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:105:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:106:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 49 previous errors + diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 62b372f4b8d9c..0603b30e34653 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -10,11 +10,15 @@ use proc_macros::external; fn main() { let v_i32 = Vec::::new(); let s_i32 = v_i32.as_slice(); + let s_i32_ref = &s_i32; + let s_i32_ref_ref = &s_i32_ref; // True positives: let _ = std::mem::size_of_val(s_i32); // WARNING let _ = std::mem::size_of_val(s_i32); // WARNING let _ = std::mem::size_of_val(s_i32) * 5; // WARNING + let _ = std::mem::size_of_val(*s_i32_ref); // WARNING + let _ = std::mem::size_of_val(**s_i32_ref_ref); // WARNING let len = s_i32.len(); let size = size_of::(); diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index d59f5fd8b9427..14093e653c09d 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -10,11 +10,15 @@ use proc_macros::external; fn main() { let v_i32 = Vec::::new(); let s_i32 = v_i32.as_slice(); + let s_i32_ref = &s_i32; + let s_i32_ref_ref = &s_i32_ref; // True positives: let _ = s_i32.len() * size_of::(); // WARNING let _ = size_of::() * s_i32.len(); // WARNING let _ = size_of::() * s_i32.len() * 5; // WARNING + let _ = size_of::() * s_i32_ref.len(); // WARNING + let _ = size_of::() * s_i32_ref_ref.len(); // WARNING let len = s_i32.len(); let size = size_of::(); diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 4bd8a4fdf17b7..0397f3a4969a8 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -1,5 +1,5 @@ error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:15:13 + --> tests/ui/manual_slice_size_calculation.rs:17:13 | LL | let _ = s_i32.len() * size_of::(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` @@ -8,40 +8,52 @@ LL | let _ = s_i32.len() * size_of::(); // WARNING = help: to override `-D warnings` add `#[allow(clippy::manual_slice_size_calculation)]` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:16:13 + --> tests/ui/manual_slice_size_calculation.rs:18:13 | LL | let _ = size_of::() * s_i32.len(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:17:13 + --> tests/ui/manual_slice_size_calculation.rs:19:13 | LL | let _ = size_of::() * s_i32.len() * 5; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:20:13 + | +LL | let _ = size_of::() * s_i32_ref.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(*s_i32_ref)` + error: manual slice size calculation --> tests/ui/manual_slice_size_calculation.rs:21:13 | +LL | let _ = size_of::() * s_i32_ref_ref.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(**s_i32_ref_ref)` + +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:25:13 + | LL | let _ = len * size_of::(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:22:13 + --> tests/ui/manual_slice_size_calculation.rs:26:13 | LL | let _ = s_i32.len() * size; // WARNING | ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:23:13 + --> tests/ui/manual_slice_size_calculation.rs:27:13 | LL | let _ = len * size; // WARNING | ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:25:13 + --> tests/ui/manual_slice_size_calculation.rs:29:13 | LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index b75ef87ab3640..71d8ac7a1f0e0 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -3,7 +3,7 @@ #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] -mod foo { +pub mod foo { pub fn foo() {} pub fn foo_bar() {} //~^ ERROR: item name starts with its containing module's name @@ -20,6 +20,22 @@ mod foo { // Should not warn pub struct Foobar; + // #8524 - shouldn't warn when item is declared in a private module... + mod error { + pub struct Error; + pub struct FooError; + } + pub use error::Error; + // ... but should still warn when the item is reexported to create a *public* path with repetition. + pub use error::FooError; + //~^ ERROR: item name starts with its containing module's name + + // FIXME: This should also warn because it creates the public path `foo::FooIter`. + mod iter { + pub struct FooIter; + } + pub use iter::*; + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. pub fn to_foo() {} pub fn into_foo() {} diff --git a/tests/ui/module_name_repetitions.stderr b/tests/ui/module_name_repetitions.stderr index bffb08f6f879f..8fd8b39487537 100644 --- a/tests/ui/module_name_repetitions.stderr +++ b/tests/ui/module_name_repetitions.stderr @@ -31,5 +31,11 @@ error: item name starts with its containing module's name LL | pub struct Foo7Bar; | ^^^^^^^ -error: aborting due to 5 previous errors +error: item name starts with its containing module's name + --> tests/ui/module_name_repetitions.rs:30:20 + | +LL | pub use error::FooError; + | ^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 5ad9aad2d0a5a..8698ed4fd678b 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -4,6 +4,9 @@ error: mutable key type LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: ... because it contains `Key`, which has interior mutability + = note: ... because it contains `AtomicUsize`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability = note: `-D clippy::mutable-key-type` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mutable_key_type)]` @@ -12,84 +15,141 @@ error: mutable key type | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^ + | + = note: ... because it contains `Key`, which has interior mutability + = note: ... because it contains `AtomicUsize`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:35:5 | LL | let _other: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Key`, which has interior mutability + = note: ... because it contains `AtomicUsize`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:63:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `(Key, U)`, which has interior mutability + = note: ... because it contains `Key`, which has interior mutability + = note: ... because it contains `AtomicUsize`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:76:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:78:5 | LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `&mut Cell`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:81:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Vec>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:83:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `BTreeMap, ()>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:85:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `BTreeMap<(), Cell>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:87:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `BTreeSet>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:89:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Option>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:91:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Option>>`, which has interior mutability + = note: ... because it contains `Vec>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:94:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Box>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:96:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Rc>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type --> tests/ui/mut_key.rs:98:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... because it contains `Arc>`, which has interior mutability + = note: ... because it contains `Cell`, which has interior mutability + = note: ... because it contains `UnsafeCell`, which has interior mutability error: aborting due to 15 previous errors diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed index 1a9c601c462ba..ab061467488a8 100644 --- a/tests/ui/needless_raw_string.fixed +++ b/tests/ui/needless_raw_string.fixed @@ -22,3 +22,12 @@ fn main() { b"no hashes"; c"no hashes"; } + +fn issue_13503() { + println!("SELECT * FROM posts"); + println!("SELECT * FROM posts"); + println!(r##"SELECT * FROM "posts""##); + + // Test arguments as well + println!("{}", "foobar".len()); +} diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs index 1126ea5aa3033..5be8bdeb4ad03 100644 --- a/tests/ui/needless_raw_string.rs +++ b/tests/ui/needless_raw_string.rs @@ -22,3 +22,12 @@ fn main() { br"no hashes"; cr"no hashes"; } + +fn issue_13503() { + println!(r"SELECT * FROM posts"); + println!(r#"SELECT * FROM posts"#); + println!(r##"SELECT * FROM "posts""##); + + // Test arguments as well + println!("{}", r"foobar".len()); +} diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr index 7d3451a03c75c..5169f08557388 100644 --- a/tests/ui/needless_raw_string.stderr +++ b/tests/ui/needless_raw_string.stderr @@ -91,5 +91,41 @@ LL - cr"no hashes"; LL + c"no hashes"; | -error: aborting due to 7 previous errors +error: unnecessary raw string literal + --> tests/ui/needless_raw_string.rs:27:14 + | +LL | println!(r"SELECT * FROM posts"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a plain string literal instead + | +LL - println!(r"SELECT * FROM posts"); +LL + println!("SELECT * FROM posts"); + | + +error: unnecessary raw string literal + --> tests/ui/needless_raw_string.rs:28:14 + | +LL | println!(r#"SELECT * FROM posts"#); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a plain string literal instead + | +LL - println!(r#"SELECT * FROM posts"#); +LL + println!("SELECT * FROM posts"); + | + +error: unnecessary raw string literal + --> tests/ui/needless_raw_string.rs:32:20 + | +LL | println!("{}", r"foobar".len()); + | ^^^^^^^^^ + | +help: use a plain string literal instead + | +LL - println!("{}", r"foobar".len()); +LL + println!("{}", "foobar".len()); + | + +error: aborting due to 10 previous errors diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed index b2ad657d6b29f..4c1137091071e 100644 --- a/tests/ui/needless_raw_string_hashes.fixed +++ b/tests/ui/needless_raw_string_hashes.fixed @@ -24,3 +24,13 @@ fn main() { r"rust"; r"hello world"; } + +fn issue_13503() { + println!(r"SELECT * FROM posts"); + println!(r"SELECT * FROM posts"); + println!(r#"SELECT * FROM "posts""#); + println!(r#"SELECT * FROM "posts""#); + + // Test arguments as well + println!("{}", r"foobar".len()); +} diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs index 54d8ed76d4751..7b6b4e784eea0 100644 --- a/tests/ui/needless_raw_string_hashes.rs +++ b/tests/ui/needless_raw_string_hashes.rs @@ -24,3 +24,13 @@ fn main() { r###"rust"###; r#"hello world"#; } + +fn issue_13503() { + println!(r"SELECT * FROM posts"); + println!(r#"SELECT * FROM posts"#); + println!(r##"SELECT * FROM "posts""##); + println!(r##"SELECT * FROM "posts""##); + + // Test arguments as well + println!("{}", r"foobar".len()); +} diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr index 96864f612c098..a213ba3e74381 100644 --- a/tests/ui/needless_raw_string_hashes.stderr +++ b/tests/ui/needless_raw_string_hashes.stderr @@ -187,5 +187,41 @@ LL - r#"hello world"#; LL + r"hello world"; | -error: aborting due to 15 previous errors +error: unnecessary hashes around raw string literal + --> tests/ui/needless_raw_string_hashes.rs:30:14 + | +LL | println!(r#"SELECT * FROM posts"#); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove all the hashes around the string literal + | +LL - println!(r#"SELECT * FROM posts"#); +LL + println!(r"SELECT * FROM posts"); + | + +error: unnecessary hashes around raw string literal + --> tests/ui/needless_raw_string_hashes.rs:31:14 + | +LL | println!(r##"SELECT * FROM "posts""##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove one hash from both sides of the string literal + | +LL - println!(r##"SELECT * FROM "posts""##); +LL + println!(r#"SELECT * FROM "posts""#); + | + +error: unnecessary hashes around raw string literal + --> tests/ui/needless_raw_string_hashes.rs:32:14 + | +LL | println!(r##"SELECT * FROM "posts""##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove one hash from both sides of the string literal + | +LL - println!(r##"SELECT * FROM "posts""##); +LL + println!(r#"SELECT * FROM "posts""#); + | + +error: aborting due to 18 previous errors diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 7452eb7768885..625d654dd3964 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -341,18 +341,18 @@ fn fn_call_in_nested_expr() { } let opt: Option = Some(1); - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or_else(f); // suggest `.unwrap_or_else(f)` // - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or_else(|| f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` // - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or_else(|| { let x = f(); x + 1 }); - //~v ERROR: use of `map_or` followed by a function call + //~v ERROR: function call inside of `map_or` let _ = opt.map_or_else(|| f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` // //~v ERROR: use of `unwrap_or` to construct default value @@ -361,7 +361,7 @@ fn fn_call_in_nested_expr() { let opt_foo = Some(Foo { val: String::from("123"), }); - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt_foo.unwrap_or_else(|| Foo { val: String::default() }); } diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index cd6f7bb207012..5b7d8faec7bff 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -341,18 +341,18 @@ fn fn_call_in_nested_expr() { } let opt: Option = Some(1); - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` // - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` // - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or({ let x = f(); x + 1 }); - //~v ERROR: use of `map_or` followed by a function call + //~v ERROR: function call inside of `map_or` let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` // //~v ERROR: use of `unwrap_or` to construct default value @@ -361,7 +361,7 @@ fn fn_call_in_nested_expr() { let opt_foo = Some(Foo { val: String::from("123"), }); - //~v ERROR: use of `unwrap_or` followed by a function call + //~v ERROR: function call inside of `unwrap_or` let _ = opt_foo.unwrap_or(Foo { val: String::default() }); } diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 06f804fb41e86..9f90a830a2114 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,4 +1,4 @@ -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:52:22 | LL | with_constructor.unwrap_or(make()); @@ -16,19 +16,19 @@ LL | with_new.unwrap_or(Vec::new()); = note: `-D clippy::unwrap-or-default` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:58:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:61:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:64:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); @@ -46,7 +46,7 @@ error: use of `unwrap_or` to construct default value LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:73:18 | LL | self_default.unwrap_or(::default()); @@ -64,7 +64,7 @@ error: use of `unwrap_or` to construct default value LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:82:21 | LL | without_default.unwrap_or(Foo::new()); @@ -100,55 +100,55 @@ error: use of `unwrap_or` to construct default value LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `ok_or` followed by a function call +error: function call inside of `ok_or` --> tests/ui/or_fun_call.rs:101:17 | LL | let _ = opt.ok_or(format!("{} world.", hello)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:105:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:107:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` -error: use of `or` followed by a function call +error: function call inside of `or` --> tests/ui/or_fun_call.rs:131:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:170:14 | LL | None.unwrap_or(ptr_to_ref(s)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:176:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:178:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` -error: use of `map_or` followed by a function call +error: function call inside of `map_or` --> tests/ui/or_fun_call.rs:253:25 | LL | let _ = Some(4).map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` -error: use of `map_or` followed by a function call +error: function call inside of `map_or` --> tests/ui/or_fun_call.rs:254:25 | LL | let _ = Some(4).map_or(g(), f); @@ -196,19 +196,19 @@ error: use of `unwrap_or_else` to construct default value LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:345:17 | LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:348:17 | LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:351:17 | LL | let _ = opt.unwrap_or({ @@ -226,7 +226,7 @@ LL + x + 1 LL ~ }); | -error: use of `map_or` followed by a function call +error: function call inside of `map_or` --> tests/ui/or_fun_call.rs:356:17 | LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` @@ -238,7 +238,7 @@ error: use of `unwrap_or` to construct default value LL | let _ = opt.unwrap_or({ i32::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/or_fun_call.rs:365:21 | LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 4fb6c08bb4495..f607a2d50c6d5 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -5,7 +5,7 @@ clippy::needless_borrow, clippy::needless_borrows_for_generic_args )] -#![warn(clippy::invalid_regex, clippy::trivial_regex)] +#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_creation_in_loops)] extern crate regex; @@ -118,7 +118,35 @@ fn trivial_regex() { let _ = BRegex::new(r"\b{start}word\b{end}"); } +fn regex_creation_in_loops() { + loop { + static STATIC_REGEX: std::sync::LazyLock = std::sync::LazyLock::new(|| Regex::new("a.b").unwrap()); + + let regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + let regex = BRegex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + #[allow(clippy::regex_creation_in_loops)] + let allowed_regex = Regex::new("a.b"); + + if true { + let regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + } + + for _ in 0..10 { + let nested_regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + } + } + + for i in 0..10 { + let dependant_regex = Regex::new(&format!("{i}")); + } +} + fn main() { syntax_error(); trivial_regex(); + regex_creation_in_loops(); } diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index e936208d8d7b6..18dd538c68b44 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -195,5 +195,55 @@ LL | let binary_trivial_empty = BRegex::new("^$"); | = help: consider using `str::is_empty` -error: aborting due to 24 previous errors +error: compiling a regex in a loop + --> tests/ui/regex.rs:125:21 + | +LL | let regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + = note: `-D clippy::regex-creation-in-loops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::regex_creation_in_loops)]` + +error: compiling a regex in a loop + --> tests/ui/regex.rs:127:21 + | +LL | let regex = BRegex::new("a.b"); + | ^^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + +error: compiling a regex in a loop + --> tests/ui/regex.rs:133:25 + | +LL | let regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + +error: compiling a regex in a loop + --> tests/ui/regex.rs:138:32 + | +LL | let nested_regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:137:9 + | +LL | for _ in 0..10 { + | ^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 7e2663d734f63..779431303aed2 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,5 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +#![feature(const_trait_impl)] use std::any::Any; @@ -144,6 +145,36 @@ fn f(obj: &dyn Derived

) { Base::<()>::is_base(obj); } +// #13476 +trait Value {} +fn const_generic + Value<1>>() {} + +// #11067 and #9626 +fn assoc_tys_generics<'a, 'b, T, U>() +where + T: IntoIterator + IntoIterator, + U: From<&'a str> + From<&'b [u16]>, +{ +} + +// #13476 +#[const_trait] +trait ConstTrait {} +const fn const_trait_bounds_good() {} + +const fn const_trait_bounds_bad() {} +//~^ trait_duplication_in_bounds + +fn projections() +where + U: ToOwned, + V: ToOwned, + T: IntoIterator, + //~^ trait_duplication_in_bounds + V: IntoIterator + IntoIterator, +{ +} + fn main() { let _x: fn(_) = f::<()>; let _x: fn(_) = f::; diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index fede1671a4363..3e974dc0a8f27 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,5 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +#![feature(const_trait_impl)] use std::any::Any; @@ -144,6 +145,36 @@ fn f(obj: &dyn Derived

) { Base::<()>::is_base(obj); } +// #13476 +trait Value {} +fn const_generic + Value<1>>() {} + +// #11067 and #9626 +fn assoc_tys_generics<'a, 'b, T, U>() +where + T: IntoIterator + IntoIterator, + U: From<&'a str> + From<&'b [u16]>, +{ +} + +// #13476 +#[const_trait] +trait ConstTrait {} +const fn const_trait_bounds_good() {} + +const fn const_trait_bounds_bad() {} +//~^ trait_duplication_in_bounds + +fn projections() +where + U: ToOwned, + V: ToOwned, + T: IntoIterator + IntoIterator, + //~^ trait_duplication_in_bounds + V: IntoIterator + IntoIterator, +{ +} + fn main() { let _x: fn(_) = f::<()>; let _x: fn(_) = f::; diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 78861fc16e817..0dd508e474507 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:6:15 + --> tests/ui/trait_duplication_in_bounds.rs:7:15 | LL | fn bad_foo(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,52 +11,64 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:12:8 + --> tests/ui/trait_duplication_in_bounds.rs:13:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:40:26 + --> tests/ui/trait_duplication_in_bounds.rs:41:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:47:15 + --> tests/ui/trait_duplication_in_bounds.rs:48:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:61:24 + --> tests/ui/trait_duplication_in_bounds.rs:62:24 | LL | trait BadTraitBound { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:68:12 + --> tests/ui/trait_duplication_in_bounds.rs:69:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:101:19 + --> tests/ui/trait_duplication_in_bounds.rs:102:19 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:109:22 + --> tests/ui/trait_duplication_in_bounds.rs:110:22 | LL | fn qualified_path(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` error: this trait bound is already specified in trait declaration - --> tests/ui/trait_duplication_in_bounds.rs:117:33 + --> tests/ui/trait_duplication_in_bounds.rs:118:33 | LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` -error: aborting due to 9 previous errors +error: these bounds contain repeated elements + --> tests/ui/trait_duplication_in_bounds.rs:165:36 + | +LL | const fn const_trait_bounds_bad() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `~const ConstTrait` + +error: these where clauses contain repeated elements + --> tests/ui/trait_duplication_in_bounds.rs:172:8 + | +LL | T: IntoIterator + IntoIterator, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator` + +error: aborting due to 11 previous errors diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 617d32d1fa793..a4a3ca82e76cd 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -84,7 +84,10 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts -#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] +#[allow( + ptr_to_integer_transmute_in_consts, + reason = "This is tested in the compiler test suite" +)] const fn issue_12402

(ptr: *const P) { // This test exists even though the compiler lints against it // to test that clippy's transmute lints do not trigger on this. diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index d68db3c2deb9f..6aa8e384e268c 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -84,7 +84,10 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts -#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] +#[allow( + ptr_to_integer_transmute_in_consts, + reason = "This is tested in the compiler test suite" +)] const fn issue_12402

(ptr: *const P) { // This test exists even though the compiler lints against it // to test that clippy's transmute lints do not trigger on this. diff --git a/tests/ui/unnecessary_literal_bound.fixed b/tests/ui/unnecessary_literal_bound.fixed new file mode 100644 index 0000000000000..107e397466d00 --- /dev/null +++ b/tests/ui/unnecessary_literal_bound.fixed @@ -0,0 +1,65 @@ +#![warn(clippy::unnecessary_literal_bound)] + +struct Struct<'a> { + not_literal: &'a str, +} + +impl Struct<'_> { + // Should warn + fn returns_lit(&self) -> &'static str { + "Hello" + } + + // Should NOT warn + fn returns_non_lit(&self) -> &str { + self.not_literal + } + + // Should warn, does not currently + fn conditionally_returns_lit(&self, cond: bool) -> &str { + if cond { "Literal" } else { "also a literal" } + } + + // Should NOT warn + fn conditionally_returns_non_lit(&self, cond: bool) -> &str { + if cond { "Literal" } else { self.not_literal } + } + + // Should warn + fn contionally_returns_literals_explicit(&self, cond: bool) -> &'static str { + if cond { + return "Literal"; + } + + "also a literal" + } + + // Should NOT warn + fn conditionally_returns_non_lit_explicit(&self, cond: bool) -> &str { + if cond { + return self.not_literal; + } + + "Literal" + } +} + +trait ReturnsStr { + fn trait_method(&self) -> &str; +} + +impl ReturnsStr for u8 { + // Should warn, even though not useful without trait refinement + fn trait_method(&self) -> &'static str { + "Literal" + } +} + +impl ReturnsStr for Struct<'_> { + // Should NOT warn + fn trait_method(&self) -> &str { + self.not_literal + } +} + +fn main() {} diff --git a/tests/ui/unnecessary_literal_bound.rs b/tests/ui/unnecessary_literal_bound.rs new file mode 100644 index 0000000000000..b371ff9d3a2e3 --- /dev/null +++ b/tests/ui/unnecessary_literal_bound.rs @@ -0,0 +1,65 @@ +#![warn(clippy::unnecessary_literal_bound)] + +struct Struct<'a> { + not_literal: &'a str, +} + +impl Struct<'_> { + // Should warn + fn returns_lit(&self) -> &str { + "Hello" + } + + // Should NOT warn + fn returns_non_lit(&self) -> &str { + self.not_literal + } + + // Should warn, does not currently + fn conditionally_returns_lit(&self, cond: bool) -> &str { + if cond { "Literal" } else { "also a literal" } + } + + // Should NOT warn + fn conditionally_returns_non_lit(&self, cond: bool) -> &str { + if cond { "Literal" } else { self.not_literal } + } + + // Should warn + fn contionally_returns_literals_explicit(&self, cond: bool) -> &str { + if cond { + return "Literal"; + } + + "also a literal" + } + + // Should NOT warn + fn conditionally_returns_non_lit_explicit(&self, cond: bool) -> &str { + if cond { + return self.not_literal; + } + + "Literal" + } +} + +trait ReturnsStr { + fn trait_method(&self) -> &str; +} + +impl ReturnsStr for u8 { + // Should warn, even though not useful without trait refinement + fn trait_method(&self) -> &str { + "Literal" + } +} + +impl ReturnsStr for Struct<'_> { + // Should NOT warn + fn trait_method(&self) -> &str { + self.not_literal + } +} + +fn main() {} diff --git a/tests/ui/unnecessary_literal_bound.stderr b/tests/ui/unnecessary_literal_bound.stderr new file mode 100644 index 0000000000000..512b2f9a0afad --- /dev/null +++ b/tests/ui/unnecessary_literal_bound.stderr @@ -0,0 +1,23 @@ +error: returning a `str` unnecessarily tied to the lifetime of arguments + --> tests/ui/unnecessary_literal_bound.rs:9:30 + | +LL | fn returns_lit(&self) -> &str { + | ^^^^ help: try: `&'static str` + | + = note: `-D clippy::unnecessary-literal-bound` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_bound)]` + +error: returning a `str` unnecessarily tied to the lifetime of arguments + --> tests/ui/unnecessary_literal_bound.rs:29:68 + | +LL | fn contionally_returns_literals_explicit(&self, cond: bool) -> &str { + | ^^^^ help: try: `&'static str` + +error: returning a `str` unnecessarily tied to the lifetime of arguments + --> tests/ui/unnecessary_literal_bound.rs:53:31 + | +LL | fn trait_method(&self) -> &str { + | ^^^^ help: try: `&'static str` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/unwrap_or.fixed b/tests/ui/unwrap_or.fixed index e1a47fc7bd940..62bc1966da6ff 100644 --- a/tests/ui/unwrap_or.fixed +++ b/tests/ui/unwrap_or.fixed @@ -3,11 +3,11 @@ fn main() { let s = Some(String::from("test string")).unwrap_or_else(|| "Fail".to_string()).len(); - //~^ ERROR: use of `unwrap_or` followed by a function call + //~^ ERROR: function call inside of `unwrap_or` //~| NOTE: `-D clippy::or-fun-call` implied by `-D warnings` } fn new_lines() { let s = Some(String::from("test string")).unwrap_or_else(|| "Fail".to_string()).len(); - //~^ ERROR: use of `unwrap_or` followed by a function call + //~^ ERROR: function call inside of `unwrap_or` } diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index 914bfb939b888..e8e4b6b7168f4 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -3,11 +3,11 @@ fn main() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - //~^ ERROR: use of `unwrap_or` followed by a function call + //~^ ERROR: function call inside of `unwrap_or` //~| NOTE: `-D clippy::or-fun-call` implied by `-D warnings` } fn new_lines() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - //~^ ERROR: use of `unwrap_or` followed by a function call + //~^ ERROR: function call inside of `unwrap_or` } diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index 6aa0b9df29b94..b712f8cf693de 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -1,4 +1,4 @@ -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/unwrap_or.rs:5:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); @@ -7,7 +7,7 @@ LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()) = note: `-D clippy::or-fun-call` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` -error: use of `unwrap_or` followed by a function call +error: function call inside of `unwrap_or` --> tests/ui/unwrap_or.rs:11:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 6832833393766..e29898f068d37 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -24,7 +24,6 @@ fn consistent_clippy_crate_versions() { let clippy_version = read_version("Cargo.toml"); let paths = [ - "declare_clippy_lint/Cargo.toml", "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", diff --git a/triagebot.toml b/triagebot.toml index dcf00e4e384b0..cd9641eedd8f8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -35,6 +35,7 @@ users_on_vacation = [ "@Alexendoo", "@dswij", "@Jarcho", + "@blyxyas", "@y21", "@Centri3", ] diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html deleted file mode 100644 index f3d7e504fdf80..0000000000000 --- a/util/gh-pages/index.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - Clippy Lints - - - - - - - - - - - - - -

-
-
-
Theme
- - -
-
- -
- - - - - - - - - - - - - diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html new file mode 100644 index 0000000000000..2412f0fd18135 --- /dev/null +++ b/util/gh-pages/index_template.html @@ -0,0 +1,232 @@ + + + {# #} + {# #} + {# #} + {# #} + {# #} + + Clippy Lints {# #} + + {# #} + {# #} + {# #} + + + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} +
{# #} + {# #} +
{# #} +
Theme
{# #} + {# #} + {# #} +
{# #} +
{# #} + +
{# #} + {# #} + + {# #} + +
{# #} +
{# #} +
{# #} +
{# #} +
{# #} + {# #} + {# #} +
{# #} +
{# #} + {# #} + {# #} +
{# #} +
{# #} + {# #} + {# #} +
{# #} +
{# #} + {# #} + {# #} +
{# #} +
{# #} +
{# #} +
{# #} + {# #} + {# #} + {# #} + {# #} + {# #} +
{# #} +
{# #} +
{# #} + {# #} + {# #} +
{# #} +
{# #} +
+ {% for lint in lints %} + + {% endfor %} +
{# #} +
{# #} + + {# #} + {# #} + {# #} + + {# #} + {# #} + {# #} + {# #} + {# #} diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 1a5330bc0e571..cc22a39b3d190 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -1,629 +1,567 @@ -(function () { - const md = window.markdownit({ - html: true, - linkify: true, - typographer: true, - highlight: function (str, lang) { - if (lang && hljs.getLanguage(lang)) { - try { - return '
' +
-                        hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
-                        '
'; - } catch (__) {} - } - - return '
' + md.utils.escapeHtml(str) + '
'; - } - }); - - function scrollToLint(lintId) { - const target = document.getElementById(lintId); - if (!target) { - return; - } - target.scrollIntoView(); - } - - function scrollToLintByURL($scope, $location) { - const removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { - scrollToLint($location.path().substring(1)); - removeListener(); - }); - } - - function selectGroup($scope, selectedGroup) { - const groups = $scope.groups; - for (const group in groups) { - if (groups.hasOwnProperty(group)) { - groups[group] = group === selectedGroup; - } +window.searchState = { + timeout: null, + inputElem: document.getElementById("search-input"), + lastSearch: '', + clearInput: () => { + searchState.inputElem.value = ""; + searchState.filterLints(); + }, + clearInputTimeout: () => { + if (searchState.timeout !== null) { + clearTimeout(searchState.timeout); + searchState.timeout = null } - } - - angular.module("clippy", []) - .filter('markdown', function ($sce) { - return function (text) { - return $sce.trustAsHtml( - md.render(text || '') - // Oh deer, what a hack :O - .replace(' { + searchState.clearInputTimeout(); + setTimeout(searchState.filterLints, 50); + }, + filterLints: () => { + function matchesSearch(lint, terms, searchStr) { + // Search by id + if (lint.elem.id.indexOf(searchStr) !== -1) { + return true; } - }) - .directive('onFinishRender', function ($timeout) { - return { - restrict: 'A', - link: function (scope, element, attr) { - if (scope.$last === true) { - $timeout(function () { - scope.$emit(attr.onFinishRender); - }); - } + // Search the description + // The use of `for`-loops instead of `foreach` enables us to return early + const docsLowerCase = lint.elem.textContent.toLowerCase(); + for (const term of terms) { + // This is more likely and will therefore be checked first + if (docsLowerCase.indexOf(term) !== -1) { + return true; } - }; - }) - .controller("lintList", function ($scope, $http, $location, $timeout) { - // Level filter - const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true}; - $scope.levels = { ...LEVEL_FILTERS_DEFAULT }; - $scope.byLevels = function (lint) { - return $scope.levels[lint.level]; - }; - - const GROUPS_FILTER_DEFAULT = { - cargo: true, - complexity: true, - correctness: true, - nursery: true, - pedantic: true, - perf: true, - restriction: true, - style: true, - suspicious: true, - deprecated: false, - } - - $scope.groups = { - ...GROUPS_FILTER_DEFAULT - }; - - $scope.versionFilters = { - "≥": {enabled: false, minorVersion: null }, - "≤": {enabled: false, minorVersion: null }, - "=": {enabled: false, minorVersion: null }, - }; - - // Map the versionFilters to the query parameters in a way that is easier to work with in a URL - const versionFilterKeyMap = { - "≥": "gte", - "≤": "lte", - "=": "eq" - }; - const reverseVersionFilterKeyMap = Object.fromEntries( - Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) - ); - - const APPLICABILITIES_FILTER_DEFAULT = { - MachineApplicable: true, - MaybeIncorrect: true, - HasPlaceholders: true, - Unspecified: true, - }; - - $scope.applicabilities = { - ...APPLICABILITIES_FILTER_DEFAULT - } - - // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them - // to corresponding $scope variables. - function loadFromURLParameters() { - // Extract parameters from URL - const urlParameters = $location.search(); - - // Define a helper function that assigns URL parameters to a provided scope variable - const handleParameter = (parameter, scopeVariable, defaultValues) => { - if (urlParameters[parameter]) { - const items = urlParameters[parameter].split(','); - for (const key in scopeVariable) { - if (scopeVariable.hasOwnProperty(key)) { - scopeVariable[key] = items.includes(key); - } - } - } else if (defaultValues) { - for (const key in defaultValues) { - if (scopeVariable.hasOwnProperty(key)) { - scopeVariable[key] = defaultValues[key]; - } - } - } - }; - - handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); - handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); - handleParameter('applicabilities', $scope.applicabilities, APPLICABILITIES_FILTER_DEFAULT); - - // Handle 'versions' parameter separately because it needs additional processing - if (urlParameters.versions) { - const versionFilters = urlParameters.versions.split(','); - for (const versionFilter of versionFilters) { - const [key, minorVersion] = versionFilter.split(':'); - const parsedMinorVersion = parseInt(minorVersion); - // Map the key from the URL parameter to its original form - const originalKey = reverseVersionFilterKeyMap[key]; - - if (originalKey in $scope.versionFilters && !isNaN(parsedMinorVersion)) { - $scope.versionFilters[originalKey].enabled = true; - $scope.versionFilters[originalKey].minorVersion = parsedMinorVersion; - } - } + if (lint.elem.id.indexOf(term) !== -1) { + return true; } - // Load the search parameter from the URL path - const searchParameter = $location.path().substring(1); // Remove the leading slash - if (searchParameter) { - $scope.search = searchParameter; - $scope.open[searchParameter] = true; - scrollToLintByURL($scope, $location); - } + return false; } + return true; + } - // updateURLParameter updates the URL parameter with the given key to the given value - function updateURLParameter(filterObj, urlKey, defaultValue = {}, processFilter = filter => filter) { - const parameter = Object.keys(filterObj) - .filter(filter => filterObj[filter]) - .sort() - .map(processFilter) - .filter(Boolean) // Filters out any falsy values, including null - .join(','); - - const defaultParameter = Object.keys(defaultValue) - .filter(filter => defaultValue[filter]) - .sort() - .map(processFilter) - .filter(Boolean) // Filters out any falsy values, including null - .join(','); - - // if we ended up back at the defaults, just remove it from the URL - if (parameter === defaultParameter) { - $location.search(urlKey, null); - } else { - $location.search(urlKey, parameter || null); - } - } + searchState.clearInputTimeout(); - // updateVersionURLParameter updates the version URL parameter with the given version filters - function updateVersionURLParameter(versionFilters) { - updateURLParameter( - versionFilters, - 'versions', {}, - versionFilter => versionFilters[versionFilter].enabled && versionFilters[versionFilter].minorVersion != null - ? `${versionFilterKeyMap[versionFilter]}:${versionFilters[versionFilter].minorVersion}` - : null - ); + let searchStr = searchState.inputElem.value.trim().toLowerCase(); + if (searchStr.startsWith("clippy::")) { + searchStr = searchStr.slice(8); + } + if (searchState.lastSearch === searchStr) { + return; + } + searchState.lastSearch = searchStr; + const terms = searchStr.split(" "); + const cleanedSearchStr = searchStr.replaceAll("-", "_"); + + for (const lint of filters.getAllLints()) { + lint.searchFilteredOut = !matchesSearch(lint, terms, cleanedSearchStr); + if (lint.filteredOut) { + continue; } - - // updateAllURLParameters updates all the URL parameters with the current filter settings - function updateAllURLParameters() { - updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); - updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); - updateVersionURLParameter($scope.versionFilters); - updateURLParameter($scope.applicabilities, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT); + if (lint.searchFilteredOut) { + lint.elem.style.display = "none"; + } else { + lint.elem.style.display = ""; } + } + if (searchStr.length > 0) { + window.location.hash = `/${searchStr}`; + } else { + window.location.hash = ''; + } + }, +}; - // Add $watches to automatically update URL parameters when the data changes - $scope.$watch('levels', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'levels', LEVEL_FILTERS_DEFAULT); - } - }, true); - - $scope.$watch('groups', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'groups', GROUPS_FILTER_DEFAULT); - } - }, true); - - $scope.$watch('versionFilters', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateVersionURLParameter(newVal); - } - }, true); - - $scope.$watch('applicabilities', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT) - } - }, true); - - // Watch for changes in the URL path and update the search and lint display - $scope.$watch(function () { return $location.path(); }, function (newPath) { - const searchParameter = newPath.substring(1); - if ($scope.search !== searchParameter) { - $scope.search = searchParameter; - $scope.open[searchParameter] = true; - scrollToLintByURL($scope, $location); - } - }); - - let debounceTimeout; - $scope.$watch('search', function (newVal, oldVal) { - if (newVal !== oldVal) { - if (debounceTimeout) { - $timeout.cancel(debounceTimeout); - } - - debounceTimeout = $timeout(function () { - $location.path(newVal); - }, 1000); - } - }); - - $scope.$watch(function () { return $location.search(); }, function (newParameters) { - loadFromURLParameters(); - }, true); - - $scope.updatePath = function () { - if (debounceTimeout) { - $timeout.cancel(debounceTimeout); - } +function handleInputChanged(event) { + if (event.target !== document.activeElement) { + return; + } + searchState.resetInputTimeout(); +} - $location.path($scope.search); - } +function handleShortcut(ev) { + if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { + return; + } - $scope.toggleLevels = function (value) { - const levels = $scope.levels; - for (const key in levels) { - if (levels.hasOwnProperty(key)) { - levels[key] = value; - } - } - }; + if (document.activeElement.tagName === "INPUT") { + if (ev.key === "Escape") { + document.activeElement.blur(); + } + } else { + switch (ev.key) { + case "s": + case "S": + case "/": + ev.preventDefault(); // To prevent the key to be put into the input. + document.getElementById("search-input").focus(); + break; + default: + break; + } + } +} - $scope.toggleGroups = function (value) { - const groups = $scope.groups; - for (const key in groups) { - if (groups.hasOwnProperty(key)) { - groups[key] = value; - } - } - }; +function toggleElements(filter, value) { + let needsUpdate = false; + let count = 0; - $scope.toggleApplicabilities = function (value) { - const applicabilities = $scope.applicabilities; - for (const key in applicabilities) { - if (applicabilities.hasOwnProperty(key)) { - applicabilities[key] = value; - } - } + const element = document.getElementById(filters[filter].id); + onEachLazy( + element.querySelectorAll("ul input"), + el => { + if (el.checked !== value) { + el.checked = value; + filters[filter][el.getAttribute("data-value")] = value; + needsUpdate = true; } + count += 1; + } + ); + element.querySelector(".badge").innerText = value ? count : 0; + if (needsUpdate) { + filters.filterLints(); + } +} - $scope.resetGroupsToDefault = function () { - $scope.groups = { - ...GROUPS_FILTER_DEFAULT - }; - }; +function changeSetting(elem) { + if (elem.id === "disable-shortcuts") { + disableShortcuts = elem.checked; + storeValue(elem.id, elem.checked); + } +} - $scope.selectedValuesCount = function (obj) { - return Object.values(obj).filter(x => x).length; - } +function onEachLazy(lazyArray, func) { + const arr = Array.prototype.slice.call(lazyArray); + for (const el of arr) { + func(el); + } +} - $scope.clearVersionFilters = function () { - for (const filter in $scope.versionFilters) { - $scope.versionFilters[filter] = { enabled: false, minorVersion: null }; - } - } +function highlightIfNeeded(elem) { + onEachLazy(elem.querySelectorAll("pre > code.language-rust:not(.highlighted)"), el => { + hljs.highlightElement(el.parentElement) + el.classList.add("highlighted"); + }); +} - $scope.versionFilterCount = function(obj) { - return Object.values(obj).filter(x => x.enabled).length; - } +function expandLint(lintId) { + const lintElem = document.getElementById(lintId); + const isCollapsed = lintElem.classList.toggle("collapsed"); + lintElem.querySelector(".label-doc-folding").innerText = isCollapsed ? "+" : "−"; + highlightIfNeeded(lintElem); +} - $scope.updateVersionFilters = function() { - for (const filter in $scope.versionFilters) { - const minorVersion = $scope.versionFilters[filter].minorVersion; +// Show details for one lint +function openLint(event) { + event.preventDefault(); + event.stopPropagation(); + expandLint(event.target.getAttribute("href").slice(1)); +} - // 1.29.0 and greater - if (minorVersion && minorVersion > 28) { - $scope.versionFilters[filter].enabled = true; - continue; - } +function copyToClipboard(event) { + event.preventDefault(); + event.stopPropagation(); - $scope.versionFilters[filter].enabled = false; - } - } + const clipboard = event.target; - $scope.byVersion = function(lint) { - const filters = $scope.versionFilters; - for (const filter in filters) { - if (filters[filter].enabled) { - const minorVersion = filters[filter].minorVersion; - - // Strip the "pre " prefix for pre 1.29.0 lints - const lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version; - const lintMinorVersion = lintVersion.substring(2, 4); - - switch (filter) { - // "=" gets the highest priority, since all filters are inclusive - case "=": - return (lintMinorVersion == minorVersion); - case "≥": - if (lintMinorVersion < minorVersion) { return false; } - break; - case "≤": - if (lintMinorVersion > minorVersion) { return false; } - break; - default: - return true - } - } - } + let resetClipboardTimeout = null; + const resetClipboardIcon = clipboard.innerHTML; - return true; - } + function resetClipboard() { + resetClipboardTimeout = null; + clipboard.innerHTML = resetClipboardIcon; + } - $scope.byGroups = function (lint) { - return $scope.groups[lint.group]; - }; + navigator.clipboard.writeText("clippy::" + clipboard.parentElement.id.slice(5)); - $scope.bySearch = function (lint, index, array) { - let searchStr = $scope.search; - // It can be `null` I haven't missed this value - if (searchStr == null) { - return true; - } - searchStr = searchStr.toLowerCase(); - if (searchStr.startsWith("clippy::")) { - searchStr = searchStr.slice(8); - } + clipboard.innerHTML = "✓"; + if (resetClipboardTimeout !== null) { + clearTimeout(resetClipboardTimeout); + } + resetClipboardTimeout = setTimeout(resetClipboard, 1000); +} - // Search by id - if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { - return true; - } +function handleBlur(event, elementId) { + const parent = document.getElementById(elementId); + if (!parent.contains(document.activeElement) && + !parent.contains(event.relatedTarget) + ) { + parent.classList.remove("open"); + } +} - // Search the description - // The use of `for`-loops instead of `foreach` enables us to return early - const terms = searchStr.split(" "); - const docsLowerCase = lint.docs.toLowerCase(); - for (index = 0; index < terms.length; index++) { - // This is more likely and will therefore be checked first - if (docsLowerCase.indexOf(terms[index]) !== -1) { - continue; - } +function toggleExpansion(expand) { + onEachLazy( + document.querySelectorAll("article"), + expand ? el => { + el.classList.remove("collapsed"); + highlightIfNeeded(el); + } : el => el.classList.add("collapsed"), + ); +} - if (lint.id.indexOf(terms[index]) !== -1) { - continue; - } +// Returns the current URL without any query parameter or hash. +function getNakedUrl() { + return window.location.href.split("?")[0].split("#")[0]; +} - return false; +const GROUPS_FILTER_DEFAULT = { + cargo: true, + complexity: true, + correctness: true, + nursery: true, + pedantic: true, + perf: true, + restriction: true, + style: true, + suspicious: true, + deprecated: false, +}; +const LEVEL_FILTERS_DEFAULT = { + allow: true, + warn: true, + deny: true, + none: true, +}; +const APPLICABILITIES_FILTER_DEFAULT = { + Unspecified: true, + MachineApplicable: true, + MaybeIncorrect: true, + HasPlaceholders: true, +}; +const URL_PARAMS_CORRESPONDANCE = { + "groups_filter": "groups", + "levels_filter": "levels", + "applicabilities_filter": "applicabilities", + "version_filter": "versions", +}; +const VERSIONS_CORRESPONDANCE = { + "lte": "≤", + "gte": "≥", + "eq": "=", +}; + +window.filters = { + groups_filter: { id: "lint-groups", ...GROUPS_FILTER_DEFAULT }, + levels_filter: { id: "lint-levels", ...LEVEL_FILTERS_DEFAULT }, + applicabilities_filter: { id: "lint-applicabilities", ...APPLICABILITIES_FILTER_DEFAULT }, + version_filter: { + "≥": null, + "≤": null, + "=": null, + }, + allLints: null, + getAllLints: () => { + if (filters.allLints === null) { + filters.allLints = Array.prototype.slice.call( + document.getElementsByTagName("article"), + ).map(elem => { + let version = elem.querySelector(".label-version").innerText; + // Strip the "pre " prefix for pre 1.29.0 lints + if (version.startsWith("pre ")) { + version = version.slice(4); } + return { + elem: elem, + group: elem.querySelector(".label-lint-group").innerText, + level: elem.querySelector(".label-lint-level").innerText, + version: parseInt(version.split(".")[1]), + applicability: elem.querySelector(".label-applicability").innerText, + filteredOut: false, + searchFilteredOut: false, + }; + }); + } + return filters.allLints; + }, + regenerateURLparams: () => { + const urlParams = new URLSearchParams(window.location.search); - return true; - } - - $scope.byApplicabilities = function (lint) { - return $scope.applicabilities[lint.applicability]; - }; - - // Show details for one lint - $scope.openLint = function (lint) { - $scope.open[lint.id] = true; - $location.path(lint.id); - }; - - $scope.toggleExpansion = function(lints, isExpanded) { - lints.forEach(lint => { - $scope.open[lint.id] = isExpanded; - }); + function compareObjects(obj1, obj2) { + return (JSON.stringify(obj1) === JSON.stringify({ id: obj1.id, ...obj2 })); + } + function updateIfNeeded(filterName, obj2) { + const obj1 = filters[filterName]; + const name = URL_PARAMS_CORRESPONDANCE[filterName]; + if (!compareObjects(obj1, obj2)) { + urlParams.set( + name, + Object.entries(obj1).filter( + ([key, value]) => value && key !== "id" + ).map( + ([key, _]) => key + ).join(","), + ); + } else { + urlParams.delete(name); } + } - $scope.copyToClipboard = function (lint) { - const clipboard = document.getElementById("clipboard-" + lint.id); - if (clipboard) { - let resetClipboardTimeout = null; - const resetClipboardIcon = clipboard.innerHTML; + updateIfNeeded("groups_filter", GROUPS_FILTER_DEFAULT); + updateIfNeeded("levels_filter", LEVEL_FILTERS_DEFAULT); + updateIfNeeded( + "applicabilities_filter", APPLICABILITIES_FILTER_DEFAULT); - function resetClipboard() { - resetClipboardTimeout = null; - clipboard.innerHTML = resetClipboardIcon; - } + const versions = []; + if (filters.version_filter["="] !== null) { + versions.push(`eq:${filters.version_filter["="]}`); + } + if (filters.version_filter["≥"] !== null) { + versions.push(`gte:${filters.version_filter["≥"]}`); + } + if (filters.version_filter["≤"] !== null) { + versions.push(`lte:${filters.version_filter["≤"]}`); + } + if (versions.length !== 0) { + urlParams.set(URL_PARAMS_CORRESPONDANCE["version_filter"], versions.join(",")); + } else { + urlParams.delete(URL_PARAMS_CORRESPONDANCE["version_filter"]); + } - navigator.clipboard.writeText("clippy::" + lint.id); + let params = urlParams.toString(); + if (params.length !== 0) { + params = `?${params}`; + } - clipboard.innerHTML = "✓"; - if (resetClipboardTimeout !== null) { - clearTimeout(resetClipboardTimeout); - } - resetClipboardTimeout = setTimeout(resetClipboard, 1000); - } + const url = getNakedUrl() + params + window.location.hash + if (!history.state) { + history.pushState(null, "", url); + } else { + history.replaceState(null, "", url); + } + }, + filterLints: () => { + // First we regenerate the URL parameters. + filters.regenerateURLparams(); + for (const lint of filters.getAllLints()) { + lint.filteredOut = (!filters.groups_filter[lint.group] + || !filters.levels_filter[lint.level] + || !filters.applicabilities_filter[lint.applicability] + || !(filters.version_filter["="] === null || lint.version === filters.version_filter["="]) + || !(filters.version_filter["≥"] === null || lint.version > filters.version_filter["≥"]) + || !(filters.version_filter["≤"] === null || lint.version < filters.version_filter["≤"]) + ); + if (lint.filteredOut || lint.searchFilteredOut) { + lint.elem.style.display = "none"; + } else { + lint.elem.style.display = ""; } - - // Get data - $scope.open = {}; - $scope.loading = true; - - // This will be used to jump into the source code of the version that this documentation is for. - $scope.docVersion = window.location.pathname.split('/')[2] || "master"; - - // Set up the filters from the URL parameters before we start loading the data - loadFromURLParameters(); - - $http.get('./lints.json') - .success(function (data) { - $scope.data = data; - $scope.loading = false; - - const selectedGroup = getQueryVariable("sel"); - if (selectedGroup) { - selectGroup($scope, selectedGroup.toLowerCase()); - } - - scrollToLintByURL($scope, $location); - - setTimeout(function () { - const el = document.getElementById('filter-input'); - if (el) { el.focus() } - }, 0); - }) - .error(function (data) { - $scope.error = data; - $scope.loading = false; - }); - }); -})(); - -function getQueryVariable(variable) { - const query = window.location.search.substring(1); - const vars = query.split('&'); - for (const entry of vars) { - const pair = entry.split('='); - if (decodeURIComponent(pair[0]) == variable) { - return decodeURIComponent(pair[1]); + } + }, +}; + +function updateFilter(elem, filter, skipLintsFiltering) { + const value = elem.getAttribute("data-value"); + if (filters[filter][value] !== elem.checked) { + filters[filter][value] = elem.checked; + const counter = document.querySelector(`#${filters[filter].id} .badge`); + counter.innerText = parseInt(counter.innerText) + (elem.checked ? 1 : -1); + if (!skipLintsFiltering) { + filters.filterLints(); } } } -function storeValue(settingName, value) { - try { - localStorage.setItem(`clippy-lint-list-${settingName}`, value); - } catch (e) { } -} - -function loadValue(settingName) { - return localStorage.getItem(`clippy-lint-list-${settingName}`); -} - -function setTheme(theme, store) { - let enableHighlight = false; - let enableNight = false; - let enableAyu = false; - - switch(theme) { - case "ayu": - enableAyu = true; - break; - case "coal": - case "navy": - enableNight = true; - break; - case "rust": - enableHighlight = true; - break; - default: - enableHighlight = true; - theme = "light"; - break; +function updateVersionFilters(elem, skipLintsFiltering) { + let value = elem.value.trim(); + if (value.length === 0) { + value = null; + } else if (/^\d+$/.test(value)) { + value = parseInt(value); + } else { + console.error(`Failed to get version number from "${value}"`); + return; } - document.getElementsByTagName("body")[0].className = theme; + const counter = document.querySelector("#version-filter .badge"); + let count = 0; + onEachLazy(document.querySelectorAll("#version-filter input"), el => { + if (el.value.trim().length !== 0) { + count += 1; + } + }); + counter.innerText = count; - document.getElementById("githubLightHighlight").disabled = enableNight || !enableHighlight; - document.getElementById("githubDarkHighlight").disabled = !enableNight && !enableAyu; + const comparisonKind = elem.getAttribute("data-value"); + if (filters.version_filter[comparisonKind] !== value) { + filters.version_filter[comparisonKind] = value; + if (!skipLintsFiltering) { + filters.filterLints(); + } + } +} - document.getElementById("styleHighlight").disabled = !enableHighlight; - document.getElementById("styleNight").disabled = !enableNight; - document.getElementById("styleAyu").disabled = !enableAyu; +function clearVersionFilters() { + let needsUpdate = false; - if (store) { - storeValue("theme", theme); - } else { - document.getElementById(`theme-choice`).value = theme; + onEachLazy(document.querySelectorAll("#version-filter input"), el => { + el.value = ""; + const comparisonKind = el.getAttribute("data-value"); + if (filters.version_filter[comparisonKind] !== null) { + needsUpdate = true; + filters.version_filter[comparisonKind] = null; + } + }); + document.querySelector("#version-filter .badge").innerText = 0; + if (needsUpdate) { + filters.filterLints(); } } -function handleShortcut(ev) { - if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { - return; +function resetGroupsToDefault() { + let needsUpdate = false; + let count = 0; + + onEachLazy(document.querySelectorAll("#lint-groups-selector input"), el => { + const key = el.getAttribute("data-value"); + const value = GROUPS_FILTER_DEFAULT[key]; + if (filters.groups_filter[key] !== value) { + filters.groups_filter[key] = value; + el.checked = value; + needsUpdate = true; + } + if (value) { + count += 1; + } + }); + document.querySelector("#lint-groups .badge").innerText = count; + if (needsUpdate) { + filters.filterLints(); } +} - if (document.activeElement.tagName === "INPUT") { - if (ev.key === "Escape") { - document.activeElement.blur(); - } - } else { - switch (ev.key) { - case "s": - case "S": - case "/": - ev.preventDefault(); // To prevent the key to be put into the input. - document.getElementById("search-input").focus(); - break; - default: - break; +function generateListOfOptions(list, elementId, filter) { + let html = ''; + let nbEnabled = 0; + for (const [key, value] of Object.entries(list)) { + const attr = value ? " checked" : ""; + html += `\ +
  • \ + \ +
  • `; + if (value) { + nbEnabled += 1; } } + + const elem = document.getElementById(`${elementId}-selector`); + elem.previousElementSibling.querySelector(".badge").innerText = `${nbEnabled}`; + elem.innerHTML += html; + + setupDropdown(elementId); } -document.addEventListener("keypress", handleShortcut); -document.addEventListener("keydown", handleShortcut); +function setupDropdown(elementId) { + const elem = document.getElementById(elementId); + const button = document.querySelector(`#${elementId} > button`); + button.onclick = () => elem.classList.toggle("open"); + + const setBlur = child => { + child.onblur = event => handleBlur(event, elementId); + }; + onEachLazy(elem.children, setBlur); + onEachLazy(elem.querySelectorAll("select"), setBlur); + onEachLazy(elem.querySelectorAll("input"), setBlur); + onEachLazy(elem.querySelectorAll("ul button"), setBlur); +} -function changeSetting(elem) { - if (elem.id === "disable-shortcuts") { - disableShortcuts = elem.checked; - storeValue(elem.id, elem.checked); +function generateSettings() { + setupDropdown("settings-dropdown"); + + generateListOfOptions(LEVEL_FILTERS_DEFAULT, "lint-levels", "levels_filter"); + generateListOfOptions(GROUPS_FILTER_DEFAULT, "lint-groups", "groups_filter"); + generateListOfOptions( + APPLICABILITIES_FILTER_DEFAULT, "lint-applicabilities", "applicabilities_filter"); + + let html = ''; + for (const kind of ["≥", "≤", "="]) { + html += `\ +
  • \ + \ + 1. \ + + .0\ +
  • `; } + document.getElementById("version-filter-selector").innerHTML += html; + setupDropdown("version-filter"); } -function onEachLazy(lazyArray, func) { - const arr = Array.prototype.slice.call(lazyArray); - for (const el of arr) { - func(el); - } +function generateSearch() { + searchState.inputElem.addEventListener("change", handleInputChanged); + searchState.inputElem.addEventListener("input", handleInputChanged); + searchState.inputElem.addEventListener("keydown", handleInputChanged); + searchState.inputElem.addEventListener("keyup", handleInputChanged); + searchState.inputElem.addEventListener("paste", handleInputChanged); } -function handleBlur(event) { - const parent = document.getElementById("settings-dropdown"); - if (!parent.contains(document.activeElement) && - !parent.contains(event.relatedTarget) - ) { - parent.classList.remove("open"); +function scrollToLint(lintId) { + const target = document.getElementById(lintId); + if (!target) { + return; } + target.scrollIntoView(); + expandLint(lintId); } -function generateSettings() { - const settings = document.getElementById("settings-dropdown"); - const settingsButton = settings.querySelector(".settings-icon") - settingsButton.onclick = () => settings.classList.toggle("open"); - settingsButton.onblur = handleBlur; - const settingsMenu = settings.querySelector(".settings-menu"); - settingsMenu.onblur = handleBlur; - onEachLazy( - settingsMenu.querySelectorAll("input"), - el => el.onblur = handleBlur, - ); +// If the page we arrive on has link to a given lint, we scroll to it. +function scrollToLintByURL() { + const lintId = window.location.hash.substring(2); + if (lintId.length > 0) { + scrollToLint(lintId); + } } -generateSettings(); +function parseURLFilters() { + const urlParams = new URLSearchParams(window.location.search); + + for (const [key, value] of urlParams.entries()) { + for (const [corres_key, corres_value] of Object.entries(URL_PARAMS_CORRESPONDANCE)) { + if (corres_value === key) { + if (key !== "versions") { + const settings = new Set(value.split(",")); + onEachLazy(document.querySelectorAll(`#lint-${key} ul input`), elem => { + elem.checked = settings.has(elem.getAttribute("data-value")); + updateFilter(elem, corres_key, true); + }); + } else { + const settings = value.split(",").map(elem => elem.split(":")); -// loading the theme after the initial load -const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); -const theme = loadValue('theme'); -if (prefersDark.matches && !theme) { - setTheme("coal", false); -} else { - setTheme(theme, false); + for (const [kind, value] of settings) { + const elem = document.querySelector( + `#version-filter input[data-value="${VERSIONS_CORRESPONDANCE[kind]}"]`); + elem.value = value; + updateVersionFilters(elem, true); + } + } + } + } + } } + +document.getElementById(`theme-choice`).value = loadValue("theme"); let disableShortcuts = loadValue('disable-shortcuts') === "true"; document.getElementById("disable-shortcuts").checked = disableShortcuts; + +document.addEventListener("keypress", handleShortcut); +document.addEventListener("keydown", handleShortcut); + +generateSettings(); +generateSearch(); +parseURLFilters(); +scrollToLintByURL(); +filters.filterLints(); diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css index a9485d511047a..a68a10b14011a 100644 --- a/util/gh-pages/style.css +++ b/util/gh-pages/style.css @@ -272,8 +272,9 @@ L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.649 height: 18px; display: block; filter: invert(0.7); - padding-left: 4px; - padding-top: 3px; + position: absolute; + top: 4px; + left: 5px; } .settings-menu * { @@ -329,6 +330,18 @@ L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.649 display: flex; } +ul.dropdown-menu li.checkbox > button { + border: 0; + width: 100%; + background: var(--theme-popup-bg); + color: var(--fg); +} + +ul.dropdown-menu li.checkbox > button:hover { + background: var(--theme-hover); + box-shadow: none; +} + #version-filter { min-width: available; } @@ -396,3 +409,37 @@ body { background: var(--bg); color: var(--fg); } + +article.collapsed .lint-docs { + display: none; +} + +.github-corner svg { + fill: var(--fg); + color: var(--bg); +} +.github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; +} +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +@media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } +} diff --git a/util/gh-pages/theme.js b/util/gh-pages/theme.js new file mode 100644 index 0000000000000..bc296955ddfbe --- /dev/null +++ b/util/gh-pages/theme.js @@ -0,0 +1,56 @@ +function storeValue(settingName, value) { + try { + localStorage.setItem(`clippy-lint-list-${settingName}`, value); + } catch (e) { } +} + +function loadValue(settingName) { + return localStorage.getItem(`clippy-lint-list-${settingName}`); +} + +function setTheme(theme, store) { + let enableHighlight = false; + let enableNight = false; + let enableAyu = false; + + switch(theme) { + case "ayu": + enableAyu = true; + break; + case "coal": + case "navy": + enableNight = true; + break; + case "rust": + enableHighlight = true; + break; + default: + enableHighlight = true; + theme = "light"; + break; + } + + document.body.className = theme; + + document.getElementById("githubLightHighlight").disabled = enableNight || !enableHighlight; + document.getElementById("githubDarkHighlight").disabled = !enableNight && !enableAyu; + + document.getElementById("styleHighlight").disabled = !enableHighlight; + document.getElementById("styleNight").disabled = !enableNight; + document.getElementById("styleAyu").disabled = !enableAyu; + + if (store) { + storeValue("theme", theme); + } +} + +(function() { + // loading the theme after the initial load + const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); + const theme = loadValue("theme"); + if (prefersDark.matches && !theme) { + setTheme("coal", false); + } else { + setTheme(theme, false); + } +})(); From 91a458f45106082f31dea172156b9ad6400a9955 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 18 Oct 2024 14:54:06 +0200 Subject: [PATCH 0063/1110] Hotfix TRAIT_METHODS static->const --- clippy_lints/src/methods/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 722290fb68e5e..2a391870d70a2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5182,7 +5182,8 @@ impl ShouldImplTraitCase { } #[rustfmt::skip] -static TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ +#[expect(clippy::large_const_arrays, reason = "`Span` is not sync, so this can't be static")] +const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), From 2c3a34a04017468ba376b045236ea6ecc36b3e71 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 18 Oct 2024 17:08:50 +0300 Subject: [PATCH 0064/1110] pulldown-cmark: don't pull getopts dep --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0e4fbdd11f879..ee9c57ab8350a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ toml = "0.7.3" walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" -pulldown-cmark = "0.11" +pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } rinja = { version = "0.3", default-features = false, features = ["config"] } # UI test dependencies From 82969e5c4e074c31cc94678d39d64bacf182a4f6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Oct 2024 00:00:10 +0200 Subject: [PATCH 0065/1110] Allow to go through clippy lints page without javascript --- util/gh-pages/index_template.html | 37 +++++++++++++++++-------------- util/gh-pages/script.js | 11 +++++---- util/gh-pages/style.css | 22 +++++++++++++++--- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 663ef1fbd31c4..c9f99000de571 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -143,26 +143,29 @@

    Clippy Lints

    {# #} {# #} {% for lint in lints %} -