From 93ef8089afa10c86a03627f6f3291451343f28e6 Mon Sep 17 00:00:00 2001 From: Aphek Date: Thu, 6 Feb 2025 23:40:49 -0300 Subject: [PATCH 01/13] Revert vita's c_char back to i8 --- library/core/src/ffi/primitives.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index ece3c7538dabb..6495e61b346fe 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -39,7 +39,6 @@ mod c_char_definition { // These are the targets on which c_char is unsigned. Usually the // signedness is the same for all target_os values on a given architecture // but there are some exceptions (see isSignedCharDefault() in clang). - // // aarch64: // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the ArmĀ® // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. @@ -97,14 +96,19 @@ mod c_char_definition { // are promoted to int as if from type signed char by default, unless the /J compilation // option is used." // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types + // Vita: + // Chars are signed by default on the Vita, and VITASDK follows that convention. + // https://github.com/vitasdk/buildscripts/blob/09c533b771591ecde88864b6acad28ffb688dbd4/patches/gcc/0001-gcc-10.patch#L33-L34 + // // L4Re: - // The kernel builds with -funsigned-char on all targets (but useserspace follows the + // The kernel builds with -funsigned-char on all targets (but userspace follows the // architecture defaults). As we only have a target for userspace apps so there are no // special cases for L4Re below. // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 if #[cfg(all( not(windows), not(target_vendor = "apple"), + not(target_os = "vita"), any( target_arch = "aarch64", target_arch = "arm", From 67cc82a704a38fcd574b0dc4373d939effed9496 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 15 Feb 2025 01:56:52 -0800 Subject: [PATCH 02/13] Inline VecDeque and BorrowedCursor methods All other methods in this file have #[inline] and these methods are very similar to those of &[u8] which are already inlined here. --- library/std/src/io/impls.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 8239b29884e8e..7885332cfde55 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -515,6 +515,7 @@ impl Read for VecDeque { Ok(n) } + #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let (front, back) = self.as_slices(); @@ -547,6 +548,7 @@ impl Read for VecDeque { Ok(()) } + #[inline] fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let len = cursor.capacity(); let (front, back) = self.as_slices(); @@ -646,6 +648,7 @@ impl Write for VecDeque { #[unstable(feature = "read_buf", issue = "78485")] impl<'a> io::Write for core::io::BorrowedCursor<'a> { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { let amt = cmp::min(buf.len(), self.capacity()); self.append(&buf[..amt]); From 41bdd2b74a8c380fb0fec1ad4d8ee21a11238a8b Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 15 Feb 2025 18:51:33 -0800 Subject: [PATCH 03/13] Override default Write methods for cursor-like types --- library/std/src/io/cursor.rs | 100 ++++++++++++++++++++++++++++++----- library/std/src/io/impls.rs | 57 +++++++++++++++++++- 2 files changed, 143 insertions(+), 14 deletions(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 08832bbc1e3d1..d7131e2fe92fd 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -439,6 +439,27 @@ fn slice_write_vectored( Ok(nwritten) } +#[inline] +fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } +} + +#[inline] +fn slice_write_all_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoSlice<'_>], +) -> io::Result<()> { + for buf in bufs { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) +} + /// Reserves the required space, and pads the vec with 0s if necessary. fn reserve_and_pad( pos_mut: &mut u64, @@ -481,9 +502,12 @@ fn reserve_and_pad( Ok(pos) } -/// Writes the slice to the vec without allocating -/// # Safety: vec must have buf.len() spare capacity -unsafe fn vec_write_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize +/// Writes the slice to the vec without allocating. +/// +/// # Safety +/// +/// `vec` must have `buf.len()` spare capacity. +unsafe fn vec_write_all_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize where A: Allocator, { @@ -492,7 +516,7 @@ where pos + buf.len() } -/// Resizing write implementation for [`Cursor`] +/// Resizing `write_all` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -501,7 +525,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result +fn vec_write_all(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result where A: Allocator, { @@ -512,7 +536,7 @@ where // Safety: we have ensured that the capacity is available // and that all bytes get written up to pos unsafe { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); if pos > vec.len() { vec.set_len(pos); } @@ -523,7 +547,7 @@ where Ok(buf_len) } -/// Resizing write_vectored implementation for [`Cursor`] +/// Resizing `write_all_vectored` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -532,7 +556,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write_vectored( +fn vec_write_all_vectored( pos_mut: &mut u64, vec: &mut Vec, bufs: &[IoSlice<'_>], @@ -550,7 +574,7 @@ where // and that all bytes get written up to the last pos unsafe { for buf in bufs { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); } if pos > vec.len() { vec.set_len(pos); @@ -579,6 +603,16 @@ impl Write for Cursor<&mut [u8]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -591,11 +625,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, self.inner, buf) + vec_write_all(&mut self.pos, self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, self.inner, bufs) + vec_write_all_vectored(&mut self.pos, self.inner, bufs) } #[inline] @@ -603,6 +637,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -615,11 +659,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, &mut self.inner, buf) + vec_write_all(&mut self.pos, &mut self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, &mut self.inner, bufs) + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs) } #[inline] @@ -627,6 +671,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, &mut self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -653,6 +707,16 @@ where true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -676,6 +740,16 @@ impl Write for Cursor<[u8; N]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 7885332cfde55..d0245f3d4984c 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -455,7 +455,17 @@ impl Write for &mut [u8] { #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) } + if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) } #[inline] @@ -495,6 +505,12 @@ impl Write for Vec { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -640,6 +656,12 @@ impl Write for VecDeque { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -655,6 +677,39 @@ impl<'a> io::Write for core::io::BorrowedCursor<'a> { Ok(amt) } + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + let n = self.write(buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) From a8d78fec52aec04254ec602851c4fd7c8469c592 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Thu, 27 Feb 2025 23:38:19 -0800 Subject: [PATCH 04/13] Specialize OsString::push for strings When concatenating two WTF-8 strings, surrogate pairs at the boundaries need to be joined. However, since UTF-8 strings cannot contain surrogate halves, this check can be skipped when one string is UTF-8. Specialize `OsString::push` to use a more efficient concatenation in this case. Unfortunately, a specialization for `T: AsRef` conflicts with `T: AsRef`, so stamp out string types with a macro. --- library/std/src/ffi/os_str.rs | 25 ++++++++++++++++++++++++- library/std/src/sys/os_str/bytes.rs | 5 +++++ library/std/src/sys/os_str/wtf8.rs | 5 +++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f4a02802336d5..c0e659db307af 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -257,7 +257,30 @@ impl OsString { #[inline] #[rustc_confusables("append", "put")] pub fn push>(&mut self, s: T) { - self.inner.push_slice(&s.as_ref().inner) + trait SpecPushTo { + fn spec_push_to(&self, buf: &mut OsString); + } + + impl> SpecPushTo for T { + #[inline] + default fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_slice(&self.as_ref().inner); + } + } + + // Use a more efficient implementation when the string is UTF-8. + macro spec_str($T:ty) { + impl SpecPushTo for $T { + #[inline] + fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_str(self); + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_push_to(self) } /// Creates a new `OsString` with at least the given capacity. diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 1d337694944bc..dfff2d3e5d31d 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -139,6 +139,11 @@ impl Buf { self.inner.extend_from_slice(&s.inner) } + #[inline] + pub fn push_str(&mut self, s: &str) { + self.inner.extend_from_slice(s.as_bytes()); + } + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 8acec6f949fc5..a32f5d40f6a9c 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -116,6 +116,11 @@ impl Buf { self.inner.push_wtf8(&s.inner) } + #[inline] + pub fn push_str(&mut self, s: &str) { + self.inner.push_str(s); + } + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) From 83407b828bcf5c883b2ab50b958edbcba0738f6a Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 28 Feb 2025 13:31:15 -0800 Subject: [PATCH 05/13] Specialize constructing OsString from strings The WTF-8 version of `OsString` tracks whether it is known to be valid UTF-8 with its `is_known_utf8` field. Specialize `From>` so this can be set for UTF-8 string types. --- library/std/src/ffi/os_str.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c0e659db307af..aa25ff5293c71 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -610,7 +610,30 @@ impl> From<&T> for OsString { /// Copies any value implementing [AsRef]<[OsStr]> /// into a newly allocated [`OsString`]. fn from(s: &T) -> OsString { - s.as_ref().to_os_string() + trait SpecToOsString { + fn spec_to_os_string(&self) -> OsString; + } + + impl> SpecToOsString for T { + #[inline] + default fn spec_to_os_string(&self) -> OsString { + self.as_ref().to_os_string() + } + } + + // Preserve the known-UTF-8 property for strings. + macro spec_str($T:ty) { + impl SpecToOsString for $T { + #[inline] + fn spec_to_os_string(&self) -> OsString { + OsString::from(String::from(self)) + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_to_os_string() } } From b1196717fcba13d8ff73ec06c3d8c5bee3b74ec9 Mon Sep 17 00:00:00 2001 From: Will Woods Date: Fri, 28 Feb 2025 17:30:53 -0800 Subject: [PATCH 06/13] Tweak BufReader::peek() doctest to expose bug in Buffer::read_more() This patch makes BufReader::peek()'s doctest call read_more() to refill the buffer before the inner reader hits EOF. This exposes a bug in read_more() that causes an out-of-bounds slice access and segfault. --- library/std/src/io/buffered/bufreader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 8b46738ab8aee..697fb5974a3dd 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -118,16 +118,16 @@ impl BufReader { /// #![feature(bufreader_peek)] /// use std::io::{Read, BufReader}; /// - /// let mut bytes = &b"oh, hello"[..]; + /// let mut bytes = &b"oh, hello there"[..]; /// let mut rdr = BufReader::with_capacity(6, &mut bytes); /// assert_eq!(rdr.peek(2).unwrap(), b"oh"); /// let mut buf = [0; 4]; /// rdr.read(&mut buf[..]).unwrap(); /// assert_eq!(&buf, b"oh, "); - /// assert_eq!(rdr.peek(2).unwrap(), b"he"); + /// assert_eq!(rdr.peek(5).unwrap(), b"hello"); /// let mut s = String::new(); /// rdr.read_to_string(&mut s).unwrap(); - /// assert_eq!(&s, "hello"); + /// assert_eq!(&s, "hello there"); /// assert_eq!(rdr.peek(1).unwrap().len(), 0); /// ``` #[unstable(feature = "bufreader_peek", issue = "128405")] From 6d07144613ffb54e6856bd5543acfe5e12eb3447 Mon Sep 17 00:00:00 2001 From: Will Woods Date: Fri, 28 Feb 2025 17:36:19 -0800 Subject: [PATCH 07/13] Fix logic error in Buffer::read_more() Buffer::read_more() is supposed to refill the buffer without discarding its contents, which are in the range `pos .. filled`. It mistakenly borrows the range `pos ..`, fills that, and then increments `filled` by the amount read. This overwrites the buffer's existing contents and sets `filled` to a too-large value that either exposes uninitialized bytes or walks off the end of the buffer entirely. This patch makes it correctly fill only the unfilled portion of the buffer, which should maintain all the type invariants and fix the test failure introduced in commit b1196717fcb. --- library/std/src/io/buffered/bufreader/buffer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 5251cc302cb49..9fd2472ebdfdb 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -109,8 +109,8 @@ impl Buffer { /// Read more bytes into the buffer without discarding any of its contents pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { - let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]); - let old_init = self.initialized - self.pos; + let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); + let old_init = self.initialized - self.filled; unsafe { buf.set_init(old_init); } From 1b21952f0279bf39d0f7188638f1a33dc16e5143 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 2 Mar 2025 13:59:00 -0800 Subject: [PATCH 08/13] Also add a MIR pre-codegen test for the derived `PartialOrd::le` --- .../derived_ord.demo_le.PreCodegen.after.mir | 91 +++++++++++++++++++ tests/mir-opt/pre-codegen/derived_ord.rs | 7 ++ 2 files changed, 98 insertions(+) create mode 100644 tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir new file mode 100644 index 0000000000000..8f47336e2a00b --- /dev/null +++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir @@ -0,0 +1,91 @@ +// MIR for `demo_le` after PreCodegen + +fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { + debug a => _1; + debug b => _2; + let mut _0: bool; + scope 1 (inlined ::le) { + let mut _11: std::option::Option; + scope 2 (inlined Option::::is_some_and:: bool {std::cmp::Ordering::is_le}>) { + let _12: std::cmp::Ordering; + scope 3 { + scope 4 (inlined bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) { + scope 5 (inlined std::cmp::Ordering::is_le) { + let mut _13: i8; + let mut _14: bool; + } + } + } + } + scope 6 (inlined ::partial_cmp) { + let mut _6: std::option::Option; + let mut _7: i8; + scope 7 { + } + scope 8 (inlined std::cmp::impls::::partial_cmp) { + let mut _3: char; + let mut _4: char; + let mut _5: std::cmp::Ordering; + } + scope 9 (inlined std::cmp::impls::::partial_cmp) { + let mut _8: i16; + let mut _9: i16; + let mut _10: std::cmp::Ordering; + } + } + } + + bb0: { + StorageLive(_12); + StorageLive(_11); + StorageLive(_5); + StorageLive(_7); + StorageLive(_3); + _3 = copy ((*_1).0: char); + StorageLive(_4); + _4 = copy ((*_2).0: char); + _5 = Cmp(move _3, move _4); + StorageDead(_4); + StorageDead(_3); + _6 = Option::::Some(copy _5); + _7 = discriminant(_5); + switchInt(move _7) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + StorageLive(_10); + StorageLive(_8); + _8 = copy ((*_1).1: i16); + StorageLive(_9); + _9 = copy ((*_2).1: i16); + _10 = Cmp(move _8, move _9); + StorageDead(_9); + StorageDead(_8); + _11 = Option::::Some(move _10); + StorageDead(_10); + StorageDead(_7); + StorageDead(_5); + goto -> bb3; + } + + bb2: { + _11 = copy _6; + StorageDead(_7); + StorageDead(_5); + goto -> bb3; + } + + bb3: { + _12 = move ((_11 as Some).0: std::cmp::Ordering); + StorageLive(_13); + StorageLive(_14); + _13 = discriminant(_12); + _14 = Eq(copy _13, const 1_i8); + _0 = Not(move _14); + StorageDead(_14); + StorageDead(_13); + StorageDead(_11); + StorageDead(_12); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs index bad751edf8419..fdfa409d5f279 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.rs +++ b/tests/mir-opt/pre-codegen/derived_ord.rs @@ -6,4 +6,11 @@ #[derive(PartialOrd, PartialEq)] pub struct MultiField(char, i16); +// Because this isn't derived by the impl, it's not on the `{impl#0}-partial_cmp`, +// and thus we need to call it to see what the inlined generic one produces. +pub fn demo_le(a: &MultiField, b: &MultiField) -> bool { + *a <= *b +} + // EMIT_MIR derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir +// EMIT_MIR derived_ord.demo_le.PreCodegen.after.mir From eae5ed609d8afe6c8cd7a231a1bbbb12aba331dd Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 2 Mar 2025 14:30:32 -0800 Subject: [PATCH 09/13] Make `is_le` and friends work like clang's --- library/core/src/cmp.rs | 22 ++++++++++++++----- .../derived_ord.demo_le.PreCodegen.after.mir | 16 ++++++-------- tests/mir-opt/pre-codegen/derived_ord.rs | 19 +++++++++++++++- ....{impl#0}-partial_cmp.PreCodegen.after.mir | 4 ++-- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index c8ced78c4d791..b29251b4b436c 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -397,6 +397,12 @@ pub enum Ordering { } impl Ordering { + #[inline] + const fn as_raw(self) -> i8 { + // FIXME(const-hack): just use `PartialOrd` against `Equal` once that's const + crate::intrinsics::discriminant_value(&self) + } + /// Returns `true` if the ordering is the `Equal` variant. /// /// # Examples @@ -413,7 +419,11 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_eq(self) -> bool { - matches!(self, Equal) + // All the `is_*` methods are implemented as comparisons against zero + // to follow how clang's libcxx implements their equivalents in + // + + self.as_raw() == 0 } /// Returns `true` if the ordering is not the `Equal` variant. @@ -432,7 +442,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ne(self) -> bool { - !matches!(self, Equal) + self.as_raw() != 0 } /// Returns `true` if the ordering is the `Less` variant. @@ -451,7 +461,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_lt(self) -> bool { - matches!(self, Less) + self.as_raw() < 0 } /// Returns `true` if the ordering is the `Greater` variant. @@ -470,7 +480,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_gt(self) -> bool { - matches!(self, Greater) + self.as_raw() > 0 } /// Returns `true` if the ordering is either the `Less` or `Equal` variant. @@ -489,7 +499,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_le(self) -> bool { - !matches!(self, Greater) + self.as_raw() <= 0 } /// Returns `true` if the ordering is either the `Greater` or `Equal` variant. @@ -508,7 +518,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ge(self) -> bool { - !matches!(self, Less) + self.as_raw() >= 0 } /// Reverses the `Ordering`. diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir index 8f47336e2a00b..49314a64c3fc9 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir @@ -12,22 +12,23 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { scope 4 (inlined bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) { scope 5 (inlined std::cmp::Ordering::is_le) { let mut _13: i8; - let mut _14: bool; + scope 6 (inlined std::cmp::Ordering::as_raw) { + } } } } } - scope 6 (inlined ::partial_cmp) { + scope 7 (inlined ::partial_cmp) { let mut _6: std::option::Option; let mut _7: i8; - scope 7 { + scope 8 { } - scope 8 (inlined std::cmp::impls::::partial_cmp) { + scope 9 (inlined std::cmp::impls::::partial_cmp) { let mut _3: char; let mut _4: char; let mut _5: std::cmp::Ordering; } - scope 9 (inlined std::cmp::impls::::partial_cmp) { + scope 10 (inlined std::cmp::impls::::partial_cmp) { let mut _8: i16; let mut _9: i16; let mut _10: std::cmp::Ordering; @@ -78,11 +79,8 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { bb3: { _12 = move ((_11 as Some).0: std::cmp::Ordering); StorageLive(_13); - StorageLive(_14); _13 = discriminant(_12); - _14 = Eq(copy _13, const 1_i8); - _0 = Not(move _14); - StorageDead(_14); + _0 = Le(move _13, const 0_i8); StorageDead(_13); StorageDead(_11); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs index fdfa409d5f279..73ae923a6cb9c 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.rs +++ b/tests/mir-opt/pre-codegen/derived_ord.rs @@ -1,4 +1,3 @@ -// skip-filecheck //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0 #![crate_type = "lib"] @@ -9,6 +8,24 @@ pub struct MultiField(char, i16); // Because this isn't derived by the impl, it's not on the `{impl#0}-partial_cmp`, // and thus we need to call it to see what the inlined generic one produces. pub fn demo_le(a: &MultiField, b: &MultiField) -> bool { + // CHECK-LABEL: fn demo_le + // CHECK: inlined ::le + // CHECK: inlined{{.+}}is_some_and + // CHECK: inlined ::partial_cmp + + // CHECK: [[A0:_[0-9]+]] = copy ((*_1).0: char); + // CHECK: [[B0:_[0-9]+]] = copy ((*_2).0: char); + // CHECK: Cmp(move [[A0]], move [[B0]]); + + // CHECK: [[D0:_[0-9]+]] = discriminant({{.+}}); + // CHECK: switchInt(move [[D0]]) -> [0: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; + + // CHECK: [[A1:_[0-9]+]] = copy ((*_1).1: i16); + // CHECK: [[B1:_[0-9]+]] = copy ((*_2).1: i16); + // CHECK: Cmp(move [[A1]], move [[B1]]); + + // CHECK: [[D1:_[0-9]+]] = discriminant({{.+}}); + // CHECK: _0 = Le(move [[D1]], const 0_i8); *a <= *b } diff --git a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir index 5f4ec1de2701f..de25eebee77ff 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir @@ -1,6 +1,6 @@ -// MIR for `::partial_cmp` after PreCodegen +// MIR for `::partial_cmp` after PreCodegen -fn ::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option { +fn ::partial_cmp(_1: &MultiField, _2: &MultiField) -> Option { debug self => _1; debug other => _2; let mut _0: std::option::Option; From ac40ea7129447abbd004859957bf00a374e8a739 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Mar 2025 17:32:32 +0000 Subject: [PATCH 10/13] Suggest typo fix for static lifetime --- .../rustc_resolve/src/late/diagnostics.rs | 48 ++++++++++++------- tests/ui/lifetimes/static-typos.rs | 7 +++ tests/ui/lifetimes/static-typos.stderr | 26 ++++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 tests/ui/lifetimes/static-typos.rs create mode 100644 tests/ui/lifetimes/static-typos.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 42be92c0f8fe5..30fb17fa6a166 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_middle::ty; use rustc_session::{Session, lint}; -use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -2874,23 +2874,35 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ) .with_span_label(lifetime_ref.ident.span, "undeclared lifetime") }; - self.suggest_introducing_lifetime( - &mut err, - Some(lifetime_ref.ident.name.as_str()), - |err, _, span, message, suggestion, span_suggs| { - err.multipart_suggestion_with_style( - message, - std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), - Applicability::MaybeIncorrect, - if span_suggs.is_empty() { - SuggestionStyle::ShowCode - } else { - SuggestionStyle::ShowAlways - }, - ); - true - }, - ); + + // Check if this is a typo of `'static`. + if edit_distance(lifetime_ref.ident.name.as_str(), "'static", 2).is_some() { + err.span_suggestion_verbose( + lifetime_ref.ident.span, + "you may have misspelled the `'static` lifetime", + "'static", + Applicability::MachineApplicable, + ); + } else { + self.suggest_introducing_lifetime( + &mut err, + Some(lifetime_ref.ident.name.as_str()), + |err, _, span, message, suggestion, span_suggs| { + err.multipart_suggestion_with_style( + message, + std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), + Applicability::MaybeIncorrect, + if span_suggs.is_empty() { + SuggestionStyle::ShowCode + } else { + SuggestionStyle::ShowAlways + }, + ); + true + }, + ); + } + err.emit(); } diff --git a/tests/ui/lifetimes/static-typos.rs b/tests/ui/lifetimes/static-typos.rs new file mode 100644 index 0000000000000..941d1b376bce9 --- /dev/null +++ b/tests/ui/lifetimes/static-typos.rs @@ -0,0 +1,7 @@ +fn stati() {} +//~^ ERROR use of undeclared lifetime name `'stati` + +fn statoc() {} +//~^ ERROR use of undeclared lifetime name `'statoc` + +fn main() {} diff --git a/tests/ui/lifetimes/static-typos.stderr b/tests/ui/lifetimes/static-typos.stderr new file mode 100644 index 0000000000000..a817fa89c7e54 --- /dev/null +++ b/tests/ui/lifetimes/static-typos.stderr @@ -0,0 +1,26 @@ +error[E0261]: use of undeclared lifetime name `'stati` + --> $DIR/static-typos.rs:1:13 + | +LL | fn stati() {} + | ^^^^^^ undeclared lifetime + | +help: you may have misspelled the `'static` lifetime + | +LL | fn stati() {} + | + + +error[E0261]: use of undeclared lifetime name `'statoc` + --> $DIR/static-typos.rs:4:14 + | +LL | fn statoc() {} + | ^^^^^^^ undeclared lifetime + | +help: you may have misspelled the `'static` lifetime + | +LL - fn statoc() {} +LL + fn statoc() {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. From 98dc15fb0f93ced1e52491b9007c27a637d37636 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Mar 2025 22:28:48 +0100 Subject: [PATCH 11/13] stabilize const_char_classify --- library/core/src/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 85cc315626d4b..bb71af339b818 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -337,7 +337,7 @@ impl char { /// '1'.is_digit(1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] + #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() @@ -886,7 +886,7 @@ impl char { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] + #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_whitespace(self) -> bool { match self { From 8f8c7fcb8bb5106bed941632847830667ad37840 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Mar 2025 22:29:07 +0100 Subject: [PATCH 12/13] stabilize const_sockaddr_setters --- library/core/src/net/socket_addr.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 9204797e6e157..57f47e66e81e7 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -200,7 +200,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { @@ -244,7 +244,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), @@ -350,7 +350,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -386,7 +386,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -448,7 +448,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -484,7 +484,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -532,7 +532,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -575,7 +575,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } From 2458ccd1f997cf9fd3451a8aaa18b333d4833d33 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 1 Mar 2025 15:23:36 -0800 Subject: [PATCH 13/13] Simplify printf and shell format suggestions --- compiler/rustc_builtin_macros/src/format.rs | 4 +--- .../rustc_builtin_macros/src/format_foreign.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6dbd8a7ac013f..12654001a1e28 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -711,11 +711,9 @@ fn report_missing_placeholders( }; let pos = sub.position(); - let sub = String::from(sub.as_str()); - if explained.contains(&sub) { + if !explained.insert(sub.to_string()) { continue; } - explained.insert(sub); if !found_foreign { found_foreign = true; diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 866ec72f11646..13d5b42942ac7 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -12,14 +12,16 @@ pub(crate) mod printf { Escape((usize, usize)), } - impl<'a> Substitution<'a> { - pub(crate) fn as_str(&self) -> &str { + impl ToString for Substitution<'_> { + fn to_string(&self) -> String { match self { - Substitution::Format(fmt) => fmt.span, - Substitution::Escape(_) => "%%", + Substitution::Format(fmt) => fmt.span.into(), + Substitution::Escape(_) => "%%".into(), } } + } + impl Substitution<'_> { pub(crate) fn position(&self) -> InnerSpan { match self { Substitution::Format(fmt) => fmt.position, @@ -627,15 +629,17 @@ pub(crate) mod shell { Escape((usize, usize)), } - impl Substitution<'_> { - pub(crate) fn as_str(&self) -> String { + impl ToString for Substitution<'_> { + fn to_string(&self) -> String { match self { Substitution::Ordinal(n, _) => format!("${n}"), Substitution::Name(n, _) => format!("${n}"), Substitution::Escape(_) => "$$".into(), } } + } + impl Substitution<'_> { pub(crate) fn position(&self) -> InnerSpan { let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; InnerSpan::new(pos.0, pos.1)