From d49d1d44995a75fd288f860c10b2bc18cfc8a5b4 Mon Sep 17 00:00:00 2001 From: PFPoitras Date: Fri, 10 Dec 2021 13:38:03 -0400 Subject: [PATCH 1/9] Modifications to buffer UTF-16 internally so that there is no longer a 4-byte buffer minimum. Include suggestions from @agausmann and @Mark-Simulacrum. --- library/std/src/sys/windows/stdio.rs | 72 +++++++++++++++++++++------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index a4fe5f67f699..8478ca043a35 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -15,7 +15,9 @@ use core::str::utf8_char_width; // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. pub struct Stdin { surrogate: u16, + incomplete_utf8: IncompleteUtf8, } + pub struct Stdout { incomplete_utf8: IncompleteUtf8, } @@ -29,6 +31,25 @@ struct IncompleteUtf8 { len: u8, } +impl IncompleteUtf8 { + // Implemented for use in Stdin::read. + fn read(&mut self, buf: &mut [u8]) -> usize { + // Write to buffer until the buffer is full or we run out of bytes. + let to_write = cmp::min(buf.len(), self.len as usize); + buf[..to_write].copy_from_slice(&self.bytes[..to_write]); + + // Rotate the remaining bytes if not enough remaining space in buffer. + if usize::from(self.len) > buf.len() { + self.bytes.copy_within(to_write.., 0); + self.len -= to_write as u8; + } else { + self.len = 0; + } + + to_write + } +} + // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see // #13304 for details). // @@ -205,7 +226,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result { impl Stdin { pub const fn new() -> Stdin { - Stdin { surrogate: 0 } + Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() } } } @@ -221,24 +242,39 @@ impl io::Read for Stdin { } } - if buf.len() == 0 { - return Ok(0); - } else if buf.len() < 4 { - return Err(io::Error::new_const( - io::ErrorKind::InvalidInput, - &"Windows stdin in console mode does not support a buffer too small to \ - guarantee holding one arbitrary UTF-8 character (4 bytes)", - )); + // If there are bytes in the incomplete utf-8, start with those. + // (No-op if there is nothing in the buffer.) + let mut bytes_copied = self.incomplete_utf8.read(buf); + + if bytes_copied == buf.len() { + return Ok(bytes_copied); + } else if buf.len() - bytes_copied < 4 { + // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. + let mut utf16_buf = [0u16; 1]; + // Read one u16 character. + let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; + // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. + let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?; + + // Read in the bytes from incomplete_utf8 until the buffer is full. + self.incomplete_utf8.len = read_bytes as u8; + // No-op if no bytes. + bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); + Ok(bytes_copied) + } else { + let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; + // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So + // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets + // lost. + let amount = cmp::min(buf.len() / 3, utf16_buf.len()); + let read = + read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; + + match utf16_to_utf8(&utf16_buf[..read], buf) { + Ok(value) => return Ok(bytes_copied + value), + Err(e) => return Err(e), + } } - - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; - // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So - // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets - // lost. - let amount = cmp::min(buf.len() / 3, utf16_buf.len()); - let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - utf16_to_utf8(&utf16_buf[..read], buf) } } From 6eb50729291c64acf0d6588dd632e9792508ca31 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 19 Dec 2021 17:36:48 +0100 Subject: [PATCH 2/9] Actually set IMAGE_SCN_LNK_REMOVE for .rmeta The code intended to set the IMAGE_SCN_LNK_REMOVE flag for the .rmeta section, however the value of this flag was set to zero. Instead use the actual value provided by the object crate. This dates back to the original introduction of this code in PR #84449, so we were never setting this flag. As I'm not on Windows, I'm not sure whether that means we were embedding .rmeta into executables, or whether the section ended up getting stripped for some other reason. --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 1df5540e3b84..a442290f39db 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -6,8 +6,8 @@ use std::path::Path; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ - elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags, - SectionKind, SymbolFlags, SymbolKind, SymbolScope, + elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; use snap::write::FrameEncoder; @@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec { ); match file.format() { BinaryFormat::Coff => { - const IMAGE_SCN_LNK_REMOVE: u32 = 0; file.section_mut(section).flags = - SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE }; + SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE }; } BinaryFormat::Elf => { - const SHF_EXCLUDE: u64 = 0x80000000; - file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE }; + file.section_mut(section).flags = + SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 }; } _ => {} }; From eb4fc640b0f881e240ad0ebb9d05f56547e42036 Mon Sep 17 00:00:00 2001 From: woppopo Date: Thu, 23 Dec 2021 22:03:12 +0900 Subject: [PATCH 3/9] Constify `Box` methods --- library/alloc/src/alloc.rs | 23 +++++-- library/alloc/src/boxed.rs | 92 ++++++++++++++++++++-------- library/alloc/src/lib.rs | 15 +++++ library/alloc/tests/boxed.rs | 114 ++++++++++++++++++++++++++++++++++- library/alloc/tests/lib.rs | 12 ++++ 5 files changed, 224 insertions(+), 32 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 66ef92558d8b..fd4b37ca6a83 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -323,17 +323,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] +#[rustc_const_unstable(feature = "const_box", issue = "none")] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +pub(crate) const unsafe fn box_free( + ptr: Unique, + alloc: A, +) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.deallocate(ptr.cast().into(), layout) + alloc.deallocate(From::from(ptr.cast()), layout) } } @@ -361,13 +365,22 @@ extern "Rust" { /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] +#[rustc_const_unstable(feature = "const_box", issue = "none")] #[cfg(all(not(no_global_oom_handling), not(test)))] #[rustc_allocator_nounwind] #[cold] -pub fn handle_alloc_error(layout: Layout) -> ! { - unsafe { - __rust_alloc_error_handler(layout.size(), layout.align()); +pub const fn handle_alloc_error(layout: Layout) -> ! { + const fn ct_error(_: Layout) -> ! { + panic!("allocation failed"); } + + fn rt_error(layout: Layout) -> ! { + unsafe { + __rust_alloc_error_handler(layout.size(), layout.align()); + } + } + + unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } } // For alloc test `std::alloc::handle_alloc_error` can be used directly. diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ab41f5646e5e..59e4ebb181fe 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -346,9 +346,13 @@ impl Box { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[must_use] #[inline] - pub fn new_in(x: T, alloc: A) -> Self { + pub const fn new_in(x: T, alloc: A) -> Self + where + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::new_uninit_in(alloc); unsafe { boxed.as_mut_ptr().write(x); @@ -372,8 +376,13 @@ impl Box { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn try_new_in(x: T, alloc: A) -> Result { + pub const fn try_new_in(x: T, alloc: A) -> Result + where + T: ~const Drop, + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::try_new_uninit_in(alloc)?; unsafe { boxed.as_mut_ptr().write(x); @@ -402,10 +411,14 @@ impl Box { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[cfg(not(no_global_oom_handling))] #[must_use] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn new_uninit_in(alloc: A) -> Box, A> { + pub const fn new_uninit_in(alloc: A) -> Box, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -439,7 +452,11 @@ impl Box { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "none")] + pub const fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); let ptr = alloc.allocate(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -466,10 +483,14 @@ impl Box { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[cfg(not(no_global_oom_handling))] // #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] - pub fn new_zeroed_in(alloc: A) -> Box, A> { + pub const fn new_zeroed_in(alloc: A) -> Box, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -503,7 +524,11 @@ impl Box { /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "none")] + pub const fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); let ptr = alloc.allocate_zeroed(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -513,20 +538,22 @@ impl Box { /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[must_use] #[inline(always)] - pub fn pin_in(x: T, alloc: A) -> Pin + pub const fn pin_in(x: T, alloc: A) -> Pin where - A: 'static, + A: 'static + ~const Allocator + ~const Drop, { - Self::new_in(x, alloc).into() + Self::into_pin(Self::new_in(x, alloc)) } /// Converts a `Box` into a `Box<[T]>` /// /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] - pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { + #[rustc_const_unstable(feature = "const_box", issue = "none")] + pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> { let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } @@ -543,8 +570,12 @@ impl Box { /// assert_eq!(Box::into_inner(c), 5); /// ``` #[unstable(feature = "box_into_inner", issue = "80437")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn into_inner(boxed: Self) -> T { + pub const fn into_inner(boxed: Self) -> T + where + Self: ~const Drop, + { *boxed } } @@ -758,8 +789,9 @@ impl Box, A> { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub unsafe fn assume_init(self) -> Box { + pub const unsafe fn assume_init(self) -> Box { let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } @@ -792,8 +824,9 @@ impl Box, A> { /// } /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn write(mut boxed: Self, value: T) -> Box { + pub const fn write(mut boxed: Self, value: T) -> Box { unsafe { (*boxed).write(value); boxed.assume_init() @@ -938,8 +971,9 @@ impl Box { /// [memory layout]: self#memory-layout /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { Box(unsafe { Unique::new_unchecked(raw) }, alloc) } @@ -1035,8 +1069,9 @@ impl Box { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { + pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -1046,9 +1081,10 @@ impl Box { issue = "none", reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead" )] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] #[doc(hidden)] - pub fn into_unique(b: Self) -> (Unique, A) { + pub const fn into_unique(b: Self) -> (Unique, A) { // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a // raw pointer for the type system. Turning it directly into a raw pointer would not be // recognized as "releasing" the unique pointer to permit aliased raw accesses, @@ -1064,8 +1100,9 @@ impl Box { /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn allocator(b: &Self) -> &A { + pub const fn allocator(b: &Self) -> &A { &b.1 } @@ -1105,8 +1142,9 @@ impl Box { /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_box", issue = "none")] #[inline] - pub fn leak<'a>(b: Self) -> &'a mut T + pub const fn leak<'a>(b: Self) -> &'a mut T where A: 'a, { @@ -1119,7 +1157,8 @@ impl Box { /// /// This is also available via [`From`]. #[unstable(feature = "box_into_pin", issue = "62370")] - pub fn into_pin(boxed: Self) -> Pin + #[rustc_const_unstable(feature = "const_box", issue = "none")] + pub const fn into_pin(boxed: Self) -> Pin where A: 'static, { @@ -1131,7 +1170,8 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { +#[rustc_const_unstable(feature = "const_box", issue = "none")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -1341,7 +1381,8 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -impl From> for Pin> +#[rustc_const_unstable(feature = "const_box", issue = "none")] +impl const From> for Pin> where A: 'static, { @@ -1720,7 +1761,8 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Box { +#[rustc_const_unstable(feature = "const_box", issue = "none")] +impl const Deref for Box { type Target = T; fn deref(&self) -> &T { @@ -1729,7 +1771,8 @@ impl Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for Box { +#[rustc_const_unstable(feature = "const_box", issue = "none")] +impl const DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self } @@ -1908,7 +1951,8 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Box where A: 'static {} +#[rustc_const_unstable(feature = "const_box", issue = "none")] +impl const Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] impl + Unpin, R, A: Allocator> Generator for Box diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 600862c4224a..d1a34e49175b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -97,8 +97,18 @@ #![feature(async_stream)] #![feature(coerce_unsized)] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] +#![feature(const_box)] #![feature(const_cow_is_borrowed)] +#![feature(const_convert)] +#![feature(const_size_of_val)] +#![feature(const_align_of_val)] +#![feature(const_ptr_read)] +#![feature(const_maybe_uninit_write)] +#![feature(const_maybe_uninit_as_mut_ptr)] +#![feature(const_refs_to_cell)] #![feature(core_intrinsics)] +#![feature(const_eval_select)] +#![feature(const_pin)] #![feature(dispatch_from_dyn)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -134,8 +144,13 @@ #![feature(box_syntax)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] +#![feature(const_deref)] #![feature(const_fn_trait_bound)] +#![feature(const_mut_refs)] +#![feature(const_ptr_write)] +#![feature(const_precise_live_drops)] #![feature(const_trait_impl)] +#![feature(const_try)] #![cfg_attr(bootstrap, feature(destructuring_assignment))] #![feature(dropck_eyepatch)] #![feature(exclusive_range_pattern)] diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index bfe66b2687ef..0d7acfed8c6a 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -1,6 +1,7 @@ -use std::cell::Cell; -use std::mem::MaybeUninit; -use std::ptr::NonNull; +use core::alloc::{AllocError, Allocator, Layout}; +use core::cell::Cell; +use core::mem::MaybeUninit; +use core::ptr::NonNull; #[test] fn uninitialized_zero_size_box() { @@ -57,3 +58,110 @@ fn box_deref_lval() { x.set(1000); assert_eq!(x.get(), 1000); } + +pub struct ConstAllocator; + +unsafe impl const Allocator for ConstAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + _ => unsafe { + let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) + }, + } + } + + unsafe fn deallocate(&self, _ptr: NonNull, layout: Layout) { + match layout.size() { + 0 => { /* do nothing */ } + _ => { /* do nothing too */ } + } + } + + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; + if layout.size() > 0 { + unsafe { + ptr.as_mut_ptr().write_bytes(0, layout.size()); + } + } + Ok(ptr) + } + + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + let new_ptr = self.grow(ptr, old_layout, new_layout)?; + if new_layout.size() > 0 { + let old_size = old_layout.size(); + let new_size = new_layout.size(); + let raw_ptr = new_ptr.as_mut_ptr(); + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + Ok(new_ptr) + } + + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + fn by_ref(&self) -> &Self + where + Self: Sized, + { + self + } +} + +#[test] +fn const_box() { + const VALUE: u32 = { + let mut boxed = Box::new_in(1u32, ConstAllocator); + assert!(*boxed == 1); + + *boxed = 42; + assert!(*boxed == 42); + + *boxed + }; + + assert!(VALUE == 42); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 68e48348b076..eec24a5c3f7e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,8 +1,19 @@ #![feature(allocator_api)] +#![feature(alloc_layout_extra)] #![feature(assert_matches)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] +#![feature(const_box)] +#![feature(const_convert)] #![feature(const_cow_is_borrowed)] +#![feature(const_heap)] +#![feature(const_intrinsic_copy)] +#![feature(const_mut_refs)] +#![feature(const_nonnull_slice_from_raw_parts)] +#![feature(const_ptr_offset)] +#![feature(const_ptr_write)] +#![feature(const_try)] +#![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] @@ -26,6 +37,7 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] +#![feature(nonnull_slice_from_raw_parts)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; From c9d2d3cc6642de70b35139dae4dd76b893a46f6b Mon Sep 17 00:00:00 2001 From: woppopo Date: Tue, 4 Jan 2022 00:35:53 +0900 Subject: [PATCH 4/9] Add tracking issues (`const_box`, `const_alloc_error`) --- library/alloc/src/alloc.rs | 4 ++-- library/alloc/src/boxed.rs | 44 +++++++++++++++++++------------------- library/alloc/src/lib.rs | 3 ++- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index fd4b37ca6a83..d075658f51a3 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -323,7 +323,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. @@ -365,7 +365,7 @@ extern "Rust" { /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] #[rustc_allocator_nounwind] #[cold] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 59e4ebb181fe..aa7344ba405a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -346,7 +346,7 @@ impl Box { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline] pub const fn new_in(x: T, alloc: A) -> Self @@ -376,7 +376,7 @@ impl Box { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn try_new_in(x: T, alloc: A) -> Result where @@ -411,7 +411,7 @@ impl Box { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] #[must_use] // #[unstable(feature = "new_uninit", issue = "63291")] @@ -452,7 +452,7 @@ impl Box { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> where A: ~const Allocator + ~const Drop, @@ -483,7 +483,7 @@ impl Box { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] // #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] @@ -524,7 +524,7 @@ impl Box { /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> where A: ~const Allocator + ~const Drop, @@ -538,7 +538,7 @@ impl Box { /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline(always)] pub const fn pin_in(x: T, alloc: A) -> Pin @@ -552,7 +552,7 @@ impl Box { /// /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> { let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } @@ -570,7 +570,7 @@ impl Box { /// assert_eq!(Box::into_inner(c), 5); /// ``` #[unstable(feature = "box_into_inner", issue = "80437")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn into_inner(boxed: Self) -> T where @@ -789,7 +789,7 @@ impl Box, A> { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const unsafe fn assume_init(self) -> Box { let (raw, alloc) = Box::into_raw_with_allocator(self); @@ -824,7 +824,7 @@ impl Box, A> { /// } /// ``` #[unstable(feature = "new_uninit", issue = "63291")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn write(mut boxed: Self, value: T) -> Box { unsafe { @@ -971,7 +971,7 @@ impl Box { /// [memory layout]: self#memory-layout /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { Box(unsafe { Unique::new_unchecked(raw) }, alloc) @@ -1069,7 +1069,7 @@ impl Box { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); @@ -1081,7 +1081,7 @@ impl Box { issue = "none", reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead" )] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] #[doc(hidden)] pub const fn into_unique(b: Self) -> (Unique, A) { @@ -1100,7 +1100,7 @@ impl Box { /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn allocator(b: &Self) -> &A { &b.1 @@ -1142,7 +1142,7 @@ impl Box { /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] pub const fn leak<'a>(b: Self) -> &'a mut T where @@ -1157,7 +1157,7 @@ impl Box { /// /// This is also available via [`From`]. #[unstable(feature = "box_into_pin", issue = "62370")] - #[rustc_const_unstable(feature = "const_box", issue = "none")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn into_pin(boxed: Self) -> Pin where A: 'static, @@ -1170,7 +1170,7 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. @@ -1381,7 +1381,7 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] impl const From> for Pin> where A: 'static, @@ -1761,7 +1761,7 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] impl const Deref for Box { type Target = T; @@ -1771,7 +1771,7 @@ impl const Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] impl const DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self @@ -1951,7 +1951,7 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -#[rustc_const_unstable(feature = "const_box", issue = "none")] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] impl const Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index d1a34e49175b..dcff4e593afd 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,8 +96,9 @@ #![feature(array_windows)] #![feature(async_stream)] #![feature(coerce_unsized)] -#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] +#![feature(const_alloc_error)] #![feature(const_box)] +#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] #![feature(const_cow_is_borrowed)] #![feature(const_convert)] #![feature(const_size_of_val)] From 51e4291f2b3c63e62a61855d162c7dd700fcb44b Mon Sep 17 00:00:00 2001 From: woppopo Date: Tue, 4 Jan 2022 01:37:53 +0900 Subject: [PATCH 5/9] Fix a compile error when no_global_oom_handling --- library/alloc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dcff4e593afd..7e663fab16af 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,7 +96,7 @@ #![feature(array_windows)] #![feature(async_stream)] #![feature(coerce_unsized)] -#![feature(const_alloc_error)] +#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![feature(const_box)] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] #![feature(const_cow_is_borrowed)] From ca3f9048a16fd817d1252f7f33a92b3a52252975 Mon Sep 17 00:00:00 2001 From: zohnannor <35764628+zohnannor@users.noreply.github.com> Date: Mon, 3 Jan 2022 20:17:57 +0300 Subject: [PATCH 6/9] Make `Receiver::into_iter` into a clickable link The documentation on `std::sync::mpsc::Iter` and `std::sync::mpsc::TryIter` provides links to the corresponding `Receiver` methods, unlike `std::sync::mpsc::IntoIter` does. This was left out in c59b188aaeadea32625534250d1f5120420be000 Related to #29377 --- library/std/src/sync/mpsc/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 2cf678ef69b0..2e54321e127c 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -429,12 +429,13 @@ pub struct TryIter<'a, T: 'a> { } /// An owning iterator over messages on a [`Receiver`], -/// created by **Receiver::into_iter**. +/// created by [`into_iter`]. /// /// This iterator will block whenever [`next`] /// is called, waiting for a new message, and [`None`] will be /// returned if the corresponding channel has hung up. /// +/// [`into_iter`]: Receiver::into_iter /// [`next`]: Iterator::next /// /// # Examples From a9698e22ec3b776114afa1296998237a5bd6522b Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 3 Jan 2022 20:25:46 +0100 Subject: [PATCH 7/9] revert #92254 "Bump gsgdt to 0.1.3" gsgdt 0.1.3 was yanked: https://github.com/rust-lang/rust/pull/92254#issuecomment-1004269481 --- Cargo.lock | 4 ++-- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_middle/src/mir/generic_graph.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a912eee97dbf..1fe03a06c797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,9 +1505,9 @@ dependencies = [ [[package]] name = "gsgdt" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60" +checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825" dependencies = [ "serde", ] diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f8d3fb6c48de..a9db8469384e 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,7 @@ doctest = false rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" either = "1.5.0" -gsgdt = "0.1.3" +gsgdt = "0.1.2" tracing = "0.1" rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index 44d0ce935df7..770b52a4d4b0 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); stmts.push(terminator_head); - Node::from_list(stmts, label, title, style) + Node::new(stmts, label, title, style) } // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so From f20ccc07489bff158b41a6bafd822366ac249cab Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Fri, 31 Dec 2021 13:32:03 +0100 Subject: [PATCH 8/9] Make the documentation of builtin macro attributes accessible - Do not `#[doc(hidden)]` the `#[derive]` macro attribute - Add a link to the reference section to `derive`'s inherent docs - Do the same for `#[test]` and `#[global_allocator]` - Fix `GlobalAlloc` link (why is it on `core` and not `alloc`?) - Try `no_inline`-ing the `std` reexports from `core` - Revert "Try `no_inline`-ing the `std` reexports from `core`" - Address PR review - Also document the unstable macros --- library/core/src/macros/mod.rs | 13 +++++++++++-- library/core/src/prelude/v1.rs | 15 ++++++--------- library/std/src/prelude/v1.rs | 19 ++++++++----------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d9389892c0cd..d8f6c85e428c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -866,7 +866,6 @@ pub(crate) mod builtin { language use and is subject to change" )] #[allow_internal_unstable(fmt_internals)] - #[doc(hidden)] #[rustc_builtin_macro] #[macro_export] macro_rules! format_args_nl { @@ -1428,6 +1427,10 @@ pub(crate) mod builtin { } /// Attribute macro used to apply derive macros. + /// + /// See [the reference] for more info. + /// + /// [the reference]: ../../../reference/attributes/derive.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] pub macro derive($item:item) { @@ -1435,6 +1438,10 @@ pub(crate) mod builtin { } /// Attribute macro applied to a function to turn it into a unit test. + /// + /// See [the reference] for more info. + /// + /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] @@ -1469,7 +1476,7 @@ pub(crate) mod builtin { /// Attribute macro applied to a static to register it as a global allocator. /// - /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html). + /// See also [`std::alloc::GlobalAlloc`](../../../std/alloc/trait.GlobalAlloc.html). #[stable(feature = "global_allocator", since = "1.28.0")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] @@ -1507,6 +1514,7 @@ pub(crate) mod builtin { since = "1.52.0", reason = "rustc-serialize is deprecated and no longer supported" )] + #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcDecodable($item:item) { /* compiler built-in */ } @@ -1519,6 +1527,7 @@ pub(crate) mod builtin { since = "1.52.0", reason = "rustc-serialize is deprecated and no longer supported" )] + #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcEncodable($item:item) { /* compiler built-in */ } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 54f498d1dc15..0fb8846288be 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -69,23 +69,21 @@ pub use crate::{ #[doc(no_inline)] pub use crate::concat_bytes; +// Do not `doc(inline)` these `doc(hidden)` items. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated, deprecated_in_future)] -#[doc(no_inline)] -pub use crate::macros::builtin::{ - bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable, -}; +#[allow(deprecated)] +pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; +// Do not `doc(no_inline)` so that they become doc items on their own +// (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[doc(no_inline)] -pub use crate::macros::builtin::derive; +pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case}; #[unstable( feature = "cfg_accessible", issue = "64797", reason = "`cfg_accessible` is not fully implemented" )] -#[doc(no_inline)] pub use crate::macros::builtin::cfg_accessible; #[unstable( @@ -93,5 +91,4 @@ pub use crate::macros::builtin::cfg_accessible; issue = "82679", reason = "`cfg_eval` is a recently implemented feature" )] -#[doc(no_inline)] pub use crate::macros::builtin::cfg_eval; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 743dd51333d1..b52bcdfca9e0 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -54,33 +54,30 @@ pub use core::prelude::v1::{ #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; -// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates -// dead links which fail link checker testing. +// Do not `doc(inline)` these `doc(hidden)` items. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated, deprecated_in_future)] -#[doc(hidden)] -pub use core::prelude::v1::{ - bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable, -}; +#[allow(deprecated)] +pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; +// Do not `doc(no_inline)` so that they become doc items on their own +// (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[doc(hidden)] -pub use core::prelude::v1::derive; +pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case}; +// Do not `doc(no_inline)` either. #[unstable( feature = "cfg_accessible", issue = "64797", reason = "`cfg_accessible` is not fully implemented" )] -#[doc(hidden)] pub use core::prelude::v1::cfg_accessible; +// Do not `doc(no_inline)` either. #[unstable( feature = "cfg_eval", issue = "82679", reason = "`cfg_eval` is a recently implemented feature" )] -#[doc(hidden)] pub use core::prelude::v1::cfg_eval; // The file so far is equivalent to src/libcore/prelude/v1.rs, From 3087c4dfb7ba1c117f6f2fec7a7206eeb026e6fa Mon Sep 17 00:00:00 2001 From: chordtoll Date: Sat, 1 Jan 2022 13:32:04 -0800 Subject: [PATCH 9/9] Suggest changing quotes when str/char type mismatch --- .../src/infer/error_reporting/mod.rs | 41 +++++++++++++++++-- src/test/ui/inference/char-as-str-multi.rs | 6 +++ .../ui/inference/char-as-str-multi.stderr | 11 +++++ .../ui/inference/char-as-str-single.fixed | 11 +++++ src/test/ui/inference/char-as-str-single.rs | 11 +++++ .../ui/inference/char-as-str-single.stderr | 29 +++++++++++++ src/test/ui/inference/str-as-char.fixed | 8 ++++ src/test/ui/inference/str-as-char.rs | 8 ++++ src/test/ui/inference/str-as-char.stderr | 16 ++++++++ src/test/ui/issues/issue-23589.stderr | 5 +++ 10 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/inference/char-as-str-multi.rs create mode 100644 src/test/ui/inference/char-as-str-multi.stderr create mode 100644 src/test/ui/inference/char-as-str-single.fixed create mode 100644 src/test/ui/inference/char-as-str-single.rs create mode 100644 src/test/ui/inference/char-as-str-single.stderr create mode 100644 src/test/ui/inference/str-as-char.fixed create mode 100644 src/test/ui/inference/str-as-char.rs create mode 100644 src/test/ui/inference/str-as-char.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9a76c05e4f62..f0c73d0c2f36 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) = trace.values { - // If a tuple of length one was expected and the found expression has - // parentheses around it, perhaps the user meant to write `(expr,)` to - // build a tuple (issue #86100) match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} + // If a tuple of length one was expected and the found expression has + // parentheses around it, perhaps the user meant to write `(expr,)` to + // build a tuple (issue #86100) (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => { if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { if let Some(code) = @@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + // If a character was expected and the found expression is a string literal + // containing a single character, perhaps the user meant to write `'c'` to + // specify a character literal (issue #92479) + (ty::Char, ty::Ref(_, r, _)) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) + { + if code.chars().nth(1).is_none() { + err.span_suggestion( + span, + "if you meant to write a `char` literal, use single quotes", + format!("'{}'", code), + Applicability::MachineApplicable, + ); + } + } + } + } + // If a string was expected and the found expression is a character literal, + // perhaps the user meant to write `"s"` to specify a string literal. + (ty::Ref(_, r, _), ty::Char) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + { + err.span_suggestion( + span, + "if you meant to write a `str` literal, use double quotes", + format!("\"{}\"", code), + Applicability::MachineApplicable, + ); + } + } + } _ => {} } } diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs new file mode 100644 index 000000000000..21bbc6f20b29 --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.rs @@ -0,0 +1,6 @@ +// When a MULTI-character string literal is used where a char should be, +// DO NOT suggest changing to single quotes. + +fn main() { + let _: char = "foo"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr new file mode 100644 index 000000000000..c3ba17a5579a --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/char-as-str-multi.rs:5:19 + | +LL | let _: char = "foo"; + | ---- ^^^^^ expected `char`, found `&str` + | | + | expected due to this + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed new file mode 100644 index 000000000000..e401492a830b --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.fixed @@ -0,0 +1,11 @@ +// When a SINGLE-character string literal is used where a char should be, +// suggest changing to single quotes. + +// Testing both single-byte and multi-byte characters, as we should handle both. + +// run-rustfix + +fn main() { + let _: char = 'a'; //~ ERROR mismatched types + let _: char = '人'; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs new file mode 100644 index 000000000000..4f23cea5354c --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.rs @@ -0,0 +1,11 @@ +// When a SINGLE-character string literal is used where a char should be, +// suggest changing to single quotes. + +// Testing both single-byte and multi-byte characters, as we should handle both. + +// run-rustfix + +fn main() { + let _: char = "a"; //~ ERROR mismatched types + let _: char = "人"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr new file mode 100644 index 000000000000..29075c15414b --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/char-as-str-single.rs:9:19 + | +LL | let _: char = "a"; + | ---- ^^^ expected `char`, found `&str` + | | + | expected due to this + | +help: if you meant to write a `char` literal, use single quotes + | +LL | let _: char = 'a'; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/char-as-str-single.rs:10:19 + | +LL | let _: char = "人"; + | ---- ^^^^ expected `char`, found `&str` + | | + | expected due to this + | +help: if you meant to write a `char` literal, use single quotes + | +LL | let _: char = '人'; + | ~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed new file mode 100644 index 000000000000..09f3dec5a175 --- /dev/null +++ b/src/test/ui/inference/str-as-char.fixed @@ -0,0 +1,8 @@ +// When a char literal is used where a str should be, +// suggest changing to double quotes. + +// run-rustfix + +fn main() { + let _: &str = "a"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs new file mode 100644 index 000000000000..7092a6124425 --- /dev/null +++ b/src/test/ui/inference/str-as-char.rs @@ -0,0 +1,8 @@ +// When a char literal is used where a str should be, +// suggest changing to double quotes. + +// run-rustfix + +fn main() { + let _: &str = 'a'; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr new file mode 100644 index 000000000000..ebbe7c80f771 --- /dev/null +++ b/src/test/ui/inference/str-as-char.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/str-as-char.rs:7:19 + | +LL | let _: &str = 'a'; + | ---- ^^^ expected `&str`, found `char` + | | + | expected due to this + | +help: if you meant to write a `str` literal, use double quotes + | +LL | let _: &str = "a"; + | ~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-23589.stderr b/src/test/ui/issues/issue-23589.stderr index d126e1bf0b53..e065e17c280f 100644 --- a/src/test/ui/issues/issue-23589.stderr +++ b/src/test/ui/issues/issue-23589.stderr @@ -12,6 +12,11 @@ error[E0308]: mismatched types | LL | let v: Vec(&str) = vec!['1', '2']; | ^^^ expected `&str`, found `char` + | +help: if you meant to write a `str` literal, use double quotes + | +LL | let v: Vec(&str) = vec!["1", '2']; + | ~~~ error: aborting due to 2 previous errors