From ba2d28fcccd622bee323ef095d10db03ec30468d Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sat, 28 Nov 2020 10:30:37 +0100 Subject: [PATCH 1/3] Add support for custom allocators in `String` --- library/alloc/src/alloc.rs | 2 +- library/alloc/src/str.rs | 6 +- library/alloc/src/string.rs | 530 +++++++++++------- src/test/debuginfo/pretty-std.rs | 7 +- src/test/ui/bad/bad-const-type.stderr | 3 + .../consider-removing-last-semi.stderr | 6 + src/test/ui/block-result/issue-13428.stderr | 6 + src/test/ui/conversion-methods.stderr | 6 + src/test/ui/deref-suggestion.stderr | 9 + src/test/ui/estr-subtyping.stderr | 3 + src/test/ui/issues/issue-53348.rs | 1 - src/test/ui/issues/issue-53348.stderr | 3 + src/test/ui/issues/issue-53692.stderr | 3 + src/test/ui/issues/issue-61106.stderr | 3 + src/test/ui/issues/issue-72690.stderr | 28 +- .../ui/json-bom-plus-crlf-multifile.stderr | 12 +- src/test/ui/json-bom-plus-crlf.stderr | 12 +- src/test/ui/mismatched_types/abridged.stderr | 6 + .../or-patterns-syntactic-fail.stderr | 3 + .../pattern/pat-type-err-formal-param.stderr | 3 + src/test/ui/span/coerce-suggestions.stderr | 8 + src/test/ui/span/issue-33884.stderr | 2 + src/test/ui/span/issue-39018.stderr | 3 + ...chain-method-call-mutation-in-place.stderr | 2 + .../ui/suggestions/const-in-struct-pat.stderr | 2 + ...gest-deref-inside-macro-issue-58298.stderr | 2 + src/test/ui/suggestions/format-borrow.stderr | 6 + src/test/ui/suggestions/issue-52820.stderr | 6 + src/test/ui/suggestions/issue-59819.stderr | 3 + src/test/ui/switched-expectations.stderr | 3 + src/test/ui/typeck/issue-67971.stderr | 3 + 31 files changed, 475 insertions(+), 217 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b1bfc2abe44ac..1d7013b26ef45 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -45,7 +45,7 @@ extern "Rust" { /// Note: while this type is unstable, the functionality it provides can be /// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] -#[derive(Copy, Clone, Default, Debug)] +#[derive(Copy, Clone, Default, Debug, Ord, PartialOrd, Eq, PartialEq)] #[cfg(not(test))] pub struct Global; diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 339592728ac24..1acb2a952bd38 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -27,6 +27,7 @@ // It's cleaner to just turn off the unused_imports warning than to fix them. #![allow(unused_imports)] +use core::alloc::AllocRef; use core::borrow::{Borrow, BorrowMut}; use core::iter::FusedIterator; use core::mem; @@ -571,6 +572,7 @@ impl str { /// ``` #[stable(feature = "str_box_extras", since = "1.20.0")] #[inline] -pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { - unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } +pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8], A>) -> Box { + let (slice, alloc) = Box::into_raw_with_alloc(v); + unsafe { Box::from_raw_in(slice as *mut str, alloc) } } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ce216e5336eb8..1b9f7011baa96 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -42,6 +42,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::alloc::AllocRef; use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; @@ -51,6 +52,7 @@ use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; use core::str::{lossy, pattern::Pattern}; +use crate::alloc::Global; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; @@ -275,8 +277,8 @@ use crate::vec::Vec; #[derive(PartialOrd, Eq, Ord)] #[cfg_attr(not(test), rustc_diagnostic_item = "string_type")] #[stable(feature = "rust1", since = "1.0.0")] -pub struct String { - vec: Vec, +pub struct String<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { + vec: Vec, } /// A possible error value when converting a `String` from a UTF-8 byte vector. @@ -314,8 +316,10 @@ pub struct String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone, PartialEq, Eq)] -pub struct FromUtf8Error { - bytes: Vec, +pub struct FromUtf8Error< + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +> { + bytes: Vec, error: Utf8Error, } @@ -361,8 +365,8 @@ impl String { #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.32.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub const fn new() -> String { - String { vec: Vec::new() } + pub const fn new() -> Self { + Self { vec: Vec::new() } } /// Creates a new empty `String` with a particular capacity. @@ -404,8 +408,8 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize) -> String { - String { vec: Vec::with_capacity(capacity) } + pub fn with_capacity(capacity: usize) -> Self { + Self { vec: Vec::with_capacity(capacity) } } // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is @@ -414,75 +418,10 @@ impl String { // NB see the slice::hack module in slice.rs for more information #[inline] #[cfg(test)] - pub fn from_str(_: &str) -> String { + pub fn from_str(_: &str) -> Self { panic!("not available with cfg(test)"); } - /// Converts a vector of bytes to a `String`. - /// - /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes - /// ([`Vec`]) is made of bytes, so this function converts between the - /// two. Not all byte slices are valid `String`s, however: `String` - /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that - /// the bytes are valid UTF-8, and then does the conversion. - /// - /// If you are sure that the byte slice is valid UTF-8, and you don't want - /// to incur the overhead of the validity check, there is an unsafe version - /// of this function, [`from_utf8_unchecked`], which has the same behavior - /// but skips the check. - /// - /// This method will take care to not copy the vector, for efficiency's - /// sake. - /// - /// If you need a [`&str`] instead of a `String`, consider - /// [`str::from_utf8`]. - /// - /// The inverse of this method is [`into_bytes`]. - /// - /// # Errors - /// - /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the - /// provided bytes are not UTF-8. The vector you moved in is also included. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // some bytes, in a vector - /// let sparkle_heart = vec![240, 159, 146, 150]; - /// - /// // We know these bytes are valid, so we'll use `unwrap()`. - /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); - /// - /// assert_eq!("💖", sparkle_heart); - /// ``` - /// - /// Incorrect bytes: - /// - /// ``` - /// // some invalid bytes, in a vector - /// let sparkle_heart = vec![0, 159, 146, 150]; - /// - /// assert!(String::from_utf8(sparkle_heart).is_err()); - /// ``` - /// - /// See the docs for [`FromUtf8Error`] for more details on what you can do - /// with this error. - /// - /// [`from_utf8_unchecked`]: String::from_utf8_unchecked - /// [`Vec`]: crate::vec::Vec - /// [`&str`]: prim@str - /// [`into_bytes`]: String::into_bytes - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_utf8(vec: Vec) -> Result { - match str::from_utf8(&vec) { - Ok(..) => Ok(String { vec }), - Err(e) => Err(FromUtf8Error { bytes: vec, error: e }), - } - } - /// Converts a slice of bytes to a string, including invalid characters. /// /// Strings are made of bytes ([`u8`]), and a slice of bytes @@ -585,7 +524,7 @@ impl String { /// assert!(String::from_utf16(v).is_err()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_utf16(v: &[u16]) -> Result { + pub fn from_utf16(v: &[u16]) -> Result { // This isn't done via collect::>() for performance reasons. // FIXME: the function can be simplified again when #48994 is closed. let mut ret = String::with_capacity(v.len()); @@ -625,10 +564,220 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_utf16_lossy(v: &[u16]) -> String { + pub fn from_utf16_lossy(v: &[u16]) -> Self { decode_utf16(v.iter().cloned()).map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)).collect() } + /// Creates a new `String` from a length, capacity, and pointer. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * The memory at `buf` needs to have been previously allocated by the + /// same allocator the standard library uses, with a required alignment of exactly 1. + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the correct value. + /// * The first `length` bytes at `buf` need to be valid UTF-8. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. + /// + /// The ownership of `buf` is effectively transferred to the + /// `String` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::mem; + /// + /// unsafe { + /// let s = String::from("hello"); + /// + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent automatically dropping the String's data + /// let mut s = mem::ManuallyDrop::new(s); + /// + /// let ptr = s.as_mut_ptr(); + /// let len = s.len(); + /// let capacity = s.capacity(); + /// + /// let s = String::from_raw_parts(ptr, len, capacity); + /// + /// assert_eq!(String::from("hello"), s); + /// } + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self { + unsafe { Self { vec: Vec::from_raw_parts(buf, length, capacity) } } + } +} + +impl String { + /// Creates a new empty `String` in the provided allocator. + /// + /// Given that the `String` is empty, this will not allocate any initial + /// buffer. While that means that this initial operation is very + /// inexpensive, it may cause excessive allocation later when you add + /// data. If you have an idea of how much data the `String` will hold, + /// consider the [`with_capacity`] method to prevent excessive + /// re-allocation. + /// + /// [`with_capacity`]: String::with_capacity + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let s = String::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + Self { vec: Vec::new_in(alloc) } + } + + /// Creates a new empty `String` with a particular capacity in the provided allocator. + /// + /// `String`s have an internal buffer to hold their data. The capacity is + /// the length of that buffer, and can be queried with the [`capacity`] + /// method. This method creates an empty `String`, but one with an initial + /// buffer that can hold `capacity` bytes. This is useful when you may be + /// appending a bunch of data to the `String`, reducing the number of + /// reallocations it needs to do. + /// + /// [`capacity`]: String::capacity + /// + /// If the given capacity is `0`, no allocation will occur, and this method + /// is identical to the [`new_in`] method. + /// + /// [`new_in`]: String::new_in + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let mut s = String::with_capacity_in(10, System); + /// + /// // The String contains no chars, even though it has capacity for more + /// assert_eq!(s.len(), 0); + /// + /// // These are all done without reallocating... + /// let cap = s.capacity(); + /// for _ in 0..10 { + /// s.push('a'); + /// } + /// + /// assert_eq!(s.capacity(), cap); + /// + /// // ...but this may make the string reallocate + /// s.push('a'); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { vec: Vec::with_capacity_in(capacity, alloc) } + } + + /// Converts a vector of bytes to a `String`. + /// + /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes + /// ([`Vec`]) is made of bytes, so this function converts between the + /// two. Not all byte slices are valid `String`s, however: `String` + /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that + /// the bytes are valid UTF-8, and then does the conversion. + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want + /// to incur the overhead of the validity check, there is an unsafe version + /// of this function, [`from_utf8_unchecked`], which has the same behavior + /// but skips the check. + /// + /// This method will take care to not copy the vector, for efficiency's + /// sake. + /// + /// If you need a [`&str`] instead of a `String`, consider + /// [`str::from_utf8`]. + /// + /// The inverse of this method is [`into_bytes`]. + /// + /// # Errors + /// + /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the + /// provided bytes are not UTF-8. The vector you moved in is also included. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so we'll use `unwrap()`. + /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// assert!(String::from_utf8(sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`FromUtf8Error`] for more details on what you can do + /// with this error. + /// + /// [`from_utf8_unchecked`]: String::from_utf8_unchecked + /// [`Vec`]: crate::vec::Vec + /// [`&str`]: prim@str + /// [`into_bytes`]: String::into_bytes + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_utf8(vec: Vec) -> Result> { + match str::from_utf8(&vec) { + Ok(..) => Ok(Self { vec }), + Err(e) => Err(FromUtf8Error { bytes: vec, error: e }), + } + } + + /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`] + /// if `v` contains any invalid data. + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn from_utf16_in(v: &[u16], alloc: A) -> Result { + // This isn't done via collect::>() for performance reasons. + // FIXME: the function can be simplified again when #48994 is closed. + let mut ret = String::with_capacity_in(v.len(), alloc); + for c in decode_utf16(v.iter().cloned()) { + if let Ok(c) = c { + ret.push(c); + } else { + return Err(FromUtf16Error(())); + } + } + Ok(ret) + } + /// Decomposes a `String` into its raw components. /// /// Returns the raw pointer to the underlying data, the length of @@ -660,7 +809,27 @@ impl String { self.vec.into_raw_parts() } - /// Creates a new `String` from a length, capacity, and pointer. + /// Decomposes a `String` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the string (in bytes), and the allocated capacity of the data + /// (in bytes). These are the same arguments in the same order as + /// the arguments to [`from_raw_parts_in`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `String`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `String` with the [`from_raw_parts_in`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts_in`]: String::from_raw_parts_in + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) { + self.vec.into_raw_parts_with_alloc() + } + + /// Creates a new `String` from a length, capacity, pointer, and allocatorand. /// /// # Safety /// @@ -681,34 +850,15 @@ impl String { /// contents of memory pointed to by the pointer at will. Ensure /// that nothing else uses the pointer after calling this /// function. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::mem; - /// - /// unsafe { - /// let s = String::from("hello"); - /// - // FIXME Update this when vec_into_raw_parts is stabilized - /// // Prevent automatically dropping the String's data - /// let mut s = mem::ManuallyDrop::new(s); - /// - /// let ptr = s.as_mut_ptr(); - /// let len = s.len(); - /// let capacity = s.capacity(); - /// - /// let s = String::from_raw_parts(ptr, len, capacity); - /// - /// assert_eq!(String::from("hello"), s); - /// } - /// ``` #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String { - unsafe { String { vec: Vec::from_raw_parts(buf, length, capacity) } } + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_parts_in( + buf: *mut u8, + length: usize, + capacity: usize, + alloc: A, + ) -> Self { + unsafe { Self { vec: Vec::from_raw_parts_in(buf, length, capacity, alloc) } } } /// Converts a vector of bytes to a `String` without checking that the @@ -741,8 +891,8 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String { - String { vec: bytes } + pub unsafe fn from_utf8_unchecked(bytes: Vec) -> Self { + Self { vec: bytes } } /// Converts a `String` into a byte vector. @@ -761,7 +911,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_bytes(self) -> Vec { + pub fn into_bytes(self) -> Vec { self.vec } @@ -1368,7 +1518,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn as_mut_vec(&mut self) -> &mut Vec { + pub unsafe fn as_mut_vec(&mut self) -> &mut Vec { &mut self.vec } @@ -1439,10 +1589,13 @@ impl String { #[inline] #[stable(feature = "string_split_off", since = "1.16.0")] #[must_use = "use `.truncate()` if you don't need the other half"] - pub fn split_off(&mut self, at: usize) -> String { + pub fn split_off(&mut self, at: usize) -> Self + where + A: Clone, + { assert!(self.is_char_boundary(at)); let other = self.vec.split_off(at); - unsafe { String::from_utf8_unchecked(other) } + unsafe { Self::from_utf8_unchecked(other) } } /// Truncates this `String`, removing all contents. @@ -1498,7 +1651,7 @@ impl String { /// assert_eq!(s, ""); /// ``` #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain<'_> + pub fn drain(&mut self, range: R) -> Drain<'_, A> where R: RangeBounds, { @@ -1583,13 +1736,13 @@ impl String { /// ``` #[stable(feature = "box_str", since = "1.4.0")] #[inline] - pub fn into_boxed_str(self) -> Box { + pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); unsafe { from_boxed_utf8_unchecked(slice) } } } -impl FromUtf8Error { +impl FromUtf8Error { /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `String`. /// /// # Examples @@ -1628,7 +1781,7 @@ impl FromUtf8Error { /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_bytes(self) -> Vec { + pub fn into_bytes(self) -> Vec { self.bytes } @@ -1662,7 +1815,7 @@ impl FromUtf8Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for FromUtf8Error { +impl fmt::Display for FromUtf8Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.error, f) } @@ -1676,9 +1829,9 @@ impl fmt::Display for FromUtf16Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for String { +impl Clone for String { fn clone(&self) -> Self { - String { vec: self.vec.clone() } + Self { vec: self.vec.clone() } } fn clone_from(&mut self, source: &Self) { @@ -1760,7 +1913,7 @@ impl<'a> FromIterator> for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for String { +impl Extend for String { fn extend>(&mut self, iter: I) { let iterator = iter.into_iter(); let (lower_bound, _) = iterator.size_hint(); @@ -1780,7 +1933,7 @@ impl Extend for String { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a> Extend<&'a char> for String { +impl<'a, A: AllocRef> Extend<&'a char> for String { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } @@ -1797,7 +1950,7 @@ impl<'a> Extend<&'a char> for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Extend<&'a str> for String { +impl<'a, A: AllocRef> Extend<&'a str> for String { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(s)); } @@ -1809,26 +1962,26 @@ impl<'a> Extend<&'a str> for String { } #[stable(feature = "box_str2", since = "1.45.0")] -impl Extend> for String { - fn extend>>(&mut self, iter: I) { +impl Extend> for String { + fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } } #[stable(feature = "extend_string", since = "1.4.0")] -impl Extend for String { - fn extend>(&mut self, iter: I) { +impl Extend> for String { + fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } #[inline] - fn extend_one(&mut self, s: String) { + fn extend_one(&mut self, s: String) { self.push_str(&s); } } #[stable(feature = "herd_cows", since = "1.19.0")] -impl<'a> Extend> for String { +impl<'a, A: AllocRef> Extend> for String { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } @@ -1851,7 +2004,7 @@ impl<'a> Extend> for String { reason = "API not fully fleshed out and ready to be stabilized", issue = "27721" )] -impl<'a, 'b> Pattern<'a> for &'b String { +impl<'a, 'b, A: AllocRef> Pattern<'a> for &'b String { type Searcher = <&'b str as Pattern<'a>>::Searcher; fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher { @@ -1885,22 +2038,22 @@ impl<'a, 'b> Pattern<'a> for &'b String { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for String { +impl PartialEq for String { #[inline] - fn eq(&self, other: &String) -> bool { + fn eq(&self, other: &Self) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &String) -> bool { + fn ne(&self, other: &Self) -> bool { PartialEq::ne(&self[..], &other[..]) } } macro_rules! impl_eq { - ($lhs:ty, $rhs: ty) => { + ($lhs:ty, $rhs: ty, $($Arg: ident),*) => { #[stable(feature = "rust1", since = "1.0.0")] #[allow(unused_lifetimes)] - impl<'a, 'b> PartialEq<$rhs> for $lhs { + impl<'a, 'b, $($Arg: AllocRef),*> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&self[..], &other[..]) @@ -1913,7 +2066,7 @@ macro_rules! impl_eq { #[stable(feature = "rust1", since = "1.0.0")] #[allow(unused_lifetimes)] - impl<'a, 'b> PartialEq<$lhs> for $rhs { + impl<'a, 'b, $($Arg: AllocRef),*> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&self[..], &other[..]) @@ -1926,11 +2079,11 @@ macro_rules! impl_eq { }; } -impl_eq! { String, str } -impl_eq! { String, &'a str } -impl_eq! { Cow<'a, str>, str } -impl_eq! { Cow<'a, str>, &'b str } -impl_eq! { Cow<'a, str>, String } +impl_eq! { String, str, A } +impl_eq! { String, &'a str, A } +impl_eq! { Cow<'a, str>, str, } +impl_eq! { Cow<'a, str>, &'b str, } +impl_eq! { Cow<'a, str>, String, A } #[stable(feature = "rust1", since = "1.0.0")] impl Default for String { @@ -1942,7 +2095,7 @@ impl Default for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for String { +impl fmt::Display for String { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) @@ -1950,7 +2103,7 @@ impl fmt::Display for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for String { +impl fmt::Debug for String { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) @@ -1958,7 +2111,7 @@ impl fmt::Debug for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for String { +impl hash::Hash for String { #[inline] fn hash(&self, hasher: &mut H) { (**self).hash(hasher) @@ -2003,11 +2156,11 @@ impl hash::Hash for String { /// let c = a.to_string() + b; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -impl Add<&str> for String { - type Output = String; +impl Add<&str> for String { + type Output = Self; #[inline] - fn add(mut self, other: &str) -> String { + fn add(mut self, other: &str) -> Self { self.push_str(other); self } @@ -2017,7 +2170,7 @@ impl Add<&str> for String { /// /// This has the same behavior as the [`push_str`][String::push_str] method. #[stable(feature = "stringaddassign", since = "1.12.0")] -impl AddAssign<&str> for String { +impl AddAssign<&str> for String { #[inline] fn add_assign(&mut self, other: &str) { self.push_str(other); @@ -2025,7 +2178,7 @@ impl AddAssign<&str> for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index> for String { +impl ops::Index> for String { type Output = str; #[inline] @@ -2034,7 +2187,7 @@ impl ops::Index> for String { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index> for String { +impl ops::Index> for String { type Output = str; #[inline] @@ -2043,7 +2196,7 @@ impl ops::Index> for String { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index> for String { +impl ops::Index> for String { type Output = str; #[inline] @@ -2052,7 +2205,7 @@ impl ops::Index> for String { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for String { +impl ops::Index for String { type Output = str; #[inline] @@ -2061,7 +2214,7 @@ impl ops::Index for String { } } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl ops::Index> for String { +impl ops::Index> for String { type Output = str; #[inline] @@ -2070,7 +2223,7 @@ impl ops::Index> for String { } } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl ops::Index> for String { +impl ops::Index> for String { type Output = str; #[inline] @@ -2080,42 +2233,42 @@ impl ops::Index> for String { } #[stable(feature = "derefmut_for_string", since = "1.3.0")] -impl ops::IndexMut> for String { +impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut str { &mut self[..][index] } } #[stable(feature = "derefmut_for_string", since = "1.3.0")] -impl ops::IndexMut> for String { +impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { &mut self[..][index] } } #[stable(feature = "derefmut_for_string", since = "1.3.0")] -impl ops::IndexMut> for String { +impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { &mut self[..][index] } } #[stable(feature = "derefmut_for_string", since = "1.3.0")] -impl ops::IndexMut for String { +impl ops::IndexMut for String { #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl ops::IndexMut> for String { +impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { IndexMut::index_mut(&mut **self, index) } } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl ops::IndexMut> for String { +impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { IndexMut::index_mut(&mut **self, index) @@ -2123,7 +2276,7 @@ impl ops::IndexMut> for String { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for String { +impl ops::Deref for String { type Target = str; #[inline] @@ -2133,7 +2286,7 @@ impl ops::Deref for String { } #[stable(feature = "derefmut_for_string", since = "1.3.0")] -impl ops::DerefMut for String { +impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } @@ -2265,7 +2418,7 @@ impl AsRef<[u8]> for String { #[stable(feature = "rust1", since = "1.0.0")] impl From<&str> for String { #[inline] - fn from(s: &str) -> String { + fn from(s: &str) -> Self { s.to_owned() } } @@ -2276,15 +2429,15 @@ impl From<&mut str> for String { /// /// The result is allocated on the heap. #[inline] - fn from(s: &mut str) -> String { + fn from(s: &mut str) -> Self { s.to_owned() } } #[stable(feature = "from_ref_string", since = "1.35.0")] -impl From<&String> for String { +impl From<&String> for String { #[inline] - fn from(s: &String) -> String { + fn from(s: &Self) -> Self { s.clone() } } @@ -2292,7 +2445,7 @@ impl From<&String> for String { // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] -impl From> for String { +impl From> for String { /// Converts the given boxed `str` slice to a `String`. /// It is notable that the `str` slice is owned. /// @@ -2307,13 +2460,14 @@ impl From> for String { /// /// assert_eq!("hello world", s3) /// ``` - fn from(s: Box) -> String { - s.into_string() + fn from(s: Box) -> Self { + let slice: Box<[u8], A> = s.into(); + Self { vec: <[u8]>::into_vec(slice) } } } #[stable(feature = "box_from_str", since = "1.20.0")] -impl From for Box { +impl From> for Box { /// Converts the given `String` to a boxed `str` slice that is owned. /// /// # Examples @@ -2327,14 +2481,14 @@ impl From for Box { /// /// assert_eq!("hello world", s3) /// ``` - fn from(s: String) -> Box { + fn from(s: String) -> Self { s.into_boxed_str() } } #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From> for String { - fn from(s: Cow<'a, str>) -> String { + fn from(s: Cow<'a, str>) -> Self { s.into_owned() } } @@ -2342,7 +2496,7 @@ impl<'a> From> for String { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Cow<'a, str> { #[inline] - fn from(s: &'a str) -> Cow<'a, str> { + fn from(s: &'a str) -> Self { Cow::Borrowed(s) } } @@ -2350,7 +2504,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From for Cow<'a, str> { #[inline] - fn from(s: String) -> Cow<'a, str> { + fn from(s: String) -> Self { Cow::Owned(s) } } @@ -2358,34 +2512,34 @@ impl<'a> From for Cow<'a, str> { #[stable(feature = "cow_from_string_ref", since = "1.28.0")] impl<'a> From<&'a String> for Cow<'a, str> { #[inline] - fn from(s: &'a String) -> Cow<'a, str> { + fn from(s: &'a String) -> Self { Cow::Borrowed(s.as_str()) } } #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator for Cow<'a, str> { - fn from_iter>(it: I) -> Cow<'a, str> { + fn from_iter>(it: I) -> Self { Cow::Owned(FromIterator::from_iter(it)) } } #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> { - fn from_iter>(it: I) -> Cow<'a, str> { + fn from_iter>(it: I) -> Self { Cow::Owned(FromIterator::from_iter(it)) } } #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator for Cow<'a, str> { - fn from_iter>(it: I) -> Cow<'a, str> { + fn from_iter>(it: I) -> Self { Cow::Owned(FromIterator::from_iter(it)) } } #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] -impl From for Vec { +impl From> for Vec { /// Converts the given `String` to a vector `Vec` that holds values of type `u8`. /// /// # Examples @@ -2400,13 +2554,13 @@ impl From for Vec { /// println!("{}", b); /// } /// ``` - fn from(string: String) -> Vec { + fn from(string: String) -> Self { string.into_bytes() } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Write for String { +impl fmt::Write for String { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { self.push_str(s); @@ -2427,9 +2581,9 @@ impl fmt::Write for String { /// /// [`drain`]: String::drain #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a> { +pub struct Drain<'a, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { /// Will be used as &'a mut String in the destructor - string: *mut String, + string: *mut String, /// Start of part to remove start: usize, /// End of part to remove @@ -2439,19 +2593,19 @@ pub struct Drain<'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_> { +impl fmt::Debug for Drain<'_, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain").field(&self.as_str()).finish() } } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_> {} +unsafe impl Sync for Drain<'_, A> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_> {} +unsafe impl Send for Drain<'_, A> {} #[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_> { +impl Drop for Drain<'_, A> { fn drop(&mut self) { unsafe { // Use Vec::drain. "Reaffirm" the bounds checks to avoid @@ -2464,7 +2618,7 @@ impl Drop for Drain<'_> { } } -impl<'a> Drain<'a> { +impl<'a, A: AllocRef> Drain<'a, A> { /// Returns the remaining (sub)string of this iterator as a slice. /// /// # Examples @@ -2499,7 +2653,7 @@ impl<'a> Drain<'a> { // } #[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_> { +impl Iterator for Drain<'_, A> { type Item = char; #[inline] @@ -2518,7 +2672,7 @@ impl Iterator for Drain<'_> { } #[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_> { +impl DoubleEndedIterator for Drain<'_, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -2526,7 +2680,7 @@ impl DoubleEndedIterator for Drain<'_> { } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_> {} +impl FusedIterator for Drain<'_, A> {} #[stable(feature = "from_char_for_string", since = "1.46.0")] impl From for String { diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 6632488171dad..381da42e9e9f5 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -1,4 +1,5 @@ // ignore-freebsd: gdb package too new +// ignore-tidy-linelength // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) // compile-flags:-g @@ -87,8 +88,8 @@ // NOTE: While string slices have a .natvis entry that works in VS & VS Code, it fails in CDB // cdb-command: dx string -// cdb-check:string : "IAMA string!" [Type: [...]::String] -// cdb-check: [] [Type: [...]::String] +// cdb-check:string : "IAMA string!" [Type: [...]::String<[...]>] +// cdb-check: [] [Type: [...]::String<[...]>] // cdb-check: [size] : 0xc [Type: [...]] // cdb-check: [capacity] : 0xc [Type: [...]] // cdb-check: [0] : 73 'I' [Type: char] @@ -113,7 +114,7 @@ // cdb-command: dx none // cdb-check:none : { None } [Type: [...]::Option] // cdb-command: dx some_string -// cdb-check:some_string : { Some "IAMA optional string!" } [[...]::Option<[...]::String>] +// cdb-check:some_string : { Some "IAMA optional string!" } [[...]::Option<[...]::String<[...]>>] #![allow(unused_variables)] use std::ffi::OsString; diff --git a/src/test/ui/bad/bad-const-type.stderr b/src/test/ui/bad/bad-const-type.stderr index a9c84b4b41cc8..f48a13a1c2e7a 100644 --- a/src/test/ui/bad/bad-const-type.stderr +++ b/src/test/ui/bad/bad-const-type.stderr @@ -6,6 +6,9 @@ LL | static i: String = 10; | | | expected struct `String`, found integer | help: try using a conversion method: `10.to_string()` + | + = note: expected struct `String` + found type `{integer}` error: aborting due to previous error diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 7c3d0165c6d3a..02e0cdcb54c56 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -8,6 +8,9 @@ LL | pub fn f() -> String { LL | 0u8; LL | "bla".to_string(); | - help: consider removing this semicolon + | + = note: expected struct `String` + found unit type `()` error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:8:15 @@ -19,6 +22,9 @@ LL | pub fn g() -> String { LL | "this won't work".to_string(); LL | "removeme".to_string(); | - help: consider removing this semicolon + | + = note: expected struct `String` + found unit type `()` error: aborting due to 2 previous errors diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 60aa2c5a6b06f..560c3ed4d16f2 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -8,6 +8,9 @@ LL | fn foo() -> String { ... LL | ; | - help: consider removing this semicolon + | + = note: expected struct `String` + found unit type `()` error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 @@ -19,6 +22,9 @@ LL | fn bar() -> String { LL | "foobar".to_string() LL | ; | - help: consider removing this semicolon + | + = note: expected struct `String` + found unit type `()` error: aborting due to 2 previous errors diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index 4f47e1fd0ffe0..6dc44be6b12f4 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -7,6 +7,9 @@ LL | let _tis_an_instants_play: String = "'Tis a fond Ambush—"; | | expected struct `String`, found `&str` | | help: try using a conversion method: `"'Tis a fond Ambush—".to_string()` | expected due to this + | + = note: expected struct `String` + found reference `&'static str` error[E0308]: mismatched types --> $DIR/conversion-methods.rs:6:40 @@ -27,6 +30,9 @@ LL | let _but_should_the_play: String = 2; // Perhaps surprisingly, we sugge | | expected struct `String`, found integer | | help: try using a conversion method: `2.to_string()` | expected due to this + | + = note: expected struct `String` + found type `{integer}` error[E0308]: mismatched types --> $DIR/conversion-methods.rs:12:47 diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index f59f05db9c047..376e65d9849dd 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -6,6 +6,9 @@ LL | foo(s); | | | expected struct `String`, found `&String` | help: try using a conversion method: `s.to_string()` + | + = note: expected struct `String` + found reference `&String` error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:14:10 @@ -24,6 +27,9 @@ LL | foo(&"aaa".to_owned()); | | | expected struct `String`, found `&String` | help: consider removing the borrow: `"aaa".to_owned()` + | + = note: expected struct `String` + found reference `&String` error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:32:9 @@ -33,6 +39,9 @@ LL | foo(&mut "aaa".to_owned()); | | | expected struct `String`, found `&mut String` | help: consider removing the borrow: `"aaa".to_owned()` + | + = note: expected struct `String` + found mutable reference `&mut String` error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:2:20 diff --git a/src/test/ui/estr-subtyping.stderr b/src/test/ui/estr-subtyping.stderr index 268ec63a80dc6..aeb12a7cd870b 100644 --- a/src/test/ui/estr-subtyping.stderr +++ b/src/test/ui/estr-subtyping.stderr @@ -6,6 +6,9 @@ LL | wants_uniq(x); | | | expected struct `String`, found `&str` | help: try using a conversion method: `x.to_string()` + | + = note: expected struct `String` + found reference `&str` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53348.rs b/src/test/ui/issues/issue-53348.rs index 65f4656b02266..5eb1f386a1a42 100644 --- a/src/test/ui/issues/issue-53348.rs +++ b/src/test/ui/issues/issue-53348.rs @@ -9,7 +9,6 @@ fn main() { for i in v { a = *i.to_string(); //~^ ERROR mismatched types - //~| NOTE expected struct `String`, found `str` v2.push(a); } } diff --git a/src/test/ui/issues/issue-53348.stderr b/src/test/ui/issues/issue-53348.stderr index 8f500261243f1..734ed254ab033 100644 --- a/src/test/ui/issues/issue-53348.stderr +++ b/src/test/ui/issues/issue-53348.stderr @@ -3,6 +3,9 @@ error[E0308]: mismatched types | LL | a = *i.to_string(); | ^^^^^^^^^^^^^^ expected struct `String`, found `str` + | + = note: expected struct `String` + found type `str` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53692.stderr b/src/test/ui/issues/issue-53692.stderr index 09c78da54bcd0..c8e4486744655 100644 --- a/src/test/ui/issues/issue-53692.stderr +++ b/src/test/ui/issues/issue-53692.stderr @@ -20,6 +20,9 @@ LL | let string: String = s.clone(); | | expected struct `String`, found `&str` | | help: try using a conversion method: `s.to_string()` | expected due to this + | + = note: expected struct `String` + found reference `&str` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-61106.stderr b/src/test/ui/issues/issue-61106.stderr index 2d841d28ee26d..eb4eb436e1cbe 100644 --- a/src/test/ui/issues/issue-61106.stderr +++ b/src/test/ui/issues/issue-61106.stderr @@ -6,6 +6,9 @@ LL | foo(x.clone()); | | | expected `&str`, found struct `String` | help: consider borrowing here: `&x` + | + = note: expected reference `&str` + found struct `String` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr index 3443cca5f3270..bd79e7d000eba 100644 --- a/src/test/ui/issues/issue-72690.stderr +++ b/src/test/ui/issues/issue-72690.stderr @@ -2,9 +2,9 @@ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:7:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0282]: type annotations needed @@ -27,54 +27,54 @@ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:19:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:25:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:33:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:41:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:47:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:55:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for reference `&_` + | ^^^^^^^^^^^^ cannot infer type for struct `String<_>` | - = note: cannot satisfy `String: From<&_>` + = note: cannot satisfy `String<_>: From<&_>` = note: required by `from` error: aborting due to 9 previous errors diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr index da8849a82844f..c444034c423ea 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -24,7 +24,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -52,7 +53,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -80,7 +82,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -108,7 +111,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` +found unit type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr index 811206f9aa076..dc0be6f69f668 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -24,7 +24,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -52,7 +53,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -80,7 +82,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` + found type `{integer}`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -108,7 +111,8 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"expected struct `String` +found unit type `()`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index b7564686cd52e..c271d4fa56aae 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -82,6 +82,9 @@ LL | 1+2 | | | expected struct `String`, found integer | help: try using a conversion method: `(1+2).to_string()` + | + = note: expected struct `String` + found type `{integer}` error[E0308]: mismatched types --> $DIR/abridged.rs:59:5 @@ -93,6 +96,9 @@ LL | -2 | | | expected struct `String`, found integer | help: try using a conversion method: `(-2).to_string()` + | + = note: expected struct `String` + found type `{integer}` error: aborting due to 8 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 861d274ab5c72..40a60d6289673 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -115,6 +115,9 @@ LL | let recovery_witness: String = 0; | | expected struct `String`, found integer | | help: try using a conversion method: `0.to_string()` | expected due to this + | + = note: expected struct `String` + found type `{integer}` error: aborting due to 16 previous errors diff --git a/src/test/ui/pattern/pat-type-err-formal-param.stderr b/src/test/ui/pattern/pat-type-err-formal-param.stderr index 206713a4bfc33..65c8cef90fddd 100644 --- a/src/test/ui/pattern/pat-type-err-formal-param.stderr +++ b/src/test/ui/pattern/pat-type-err-formal-param.stderr @@ -5,6 +5,9 @@ LL | fn foo(Tuple(_): String) {} | ^^^^^^^^ ------ expected due to this | | | expected struct `String`, found struct `Tuple` + | + = note: expected struct `String` + found struct `Tuple` error: aborting due to previous error diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 857c3081c62ef..c93e3e5cefe81 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -5,6 +5,9 @@ LL | let x: usize = String::new(); | ----- ^^^^^^^^^^^^^ expected `usize`, found struct `String` | | | expected due to this + | + = note: expected type `usize` + found struct `String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:9:19 @@ -15,6 +18,9 @@ LL | let x: &str = String::new(); | | expected `&str`, found struct `String` | | help: consider borrowing here: `&String::new()` | expected due to this + | + = note: expected reference `&str` + found struct `String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:12:10 @@ -49,6 +55,8 @@ error[E0308]: mismatched types LL | s = format!("foo"); | ^^^^^^^^^^^^^^ expected `&mut String`, found struct `String` | + = note: expected mutable reference `&mut String` + found struct `String` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr index 473d36c2ab1e3..c407ec5a7b472 100644 --- a/src/test/ui/span/issue-33884.stderr +++ b/src/test/ui/span/issue-33884.stderr @@ -4,6 +4,8 @@ error[E0308]: mismatched types LL | stream.write_fmt(format!("message received")) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Arguments`, found struct `String` | + = note: expected struct `Arguments<'_>` + found struct `String` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index a7131ab8af56f..d59d5c9fbbdba 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -72,6 +72,9 @@ LL | let _ = a + b; | | | expected `&str`, found struct `String` | help: consider borrowing here: `&b` + | + = note: expected reference `&str` + found struct `String` error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:30:15 diff --git a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr index 965dbb9679d24..8dd5b2d1c2c6c 100644 --- a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr +++ b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr @@ -6,6 +6,8 @@ LL | fn foo(mut s: String) -> String { LL | s.push_str("asdf") | ^^^^^^^^^^^^^^^^^^ expected struct `String`, found `()` | + = note: expected struct `String` + found unit type `()` note: method `push_str` modifies its receiver in-place --> $DIR/chain-method-call-mutation-in-place.rs:3:7 | diff --git a/src/test/ui/suggestions/const-in-struct-pat.stderr b/src/test/ui/suggestions/const-in-struct-pat.stderr index df9c230eefdc9..ce8982cca504b 100644 --- a/src/test/ui/suggestions/const-in-struct-pat.stderr +++ b/src/test/ui/suggestions/const-in-struct-pat.stderr @@ -10,6 +10,8 @@ LL | let Thing { foo } = t; | expected struct `String`, found struct `foo` | `foo` is interpreted as a unit struct, not a new binding | + = note: expected struct `String` + found struct `foo` help: bind the struct field to a different name instead | LL | let Thing { foo: other_foo } = t; diff --git a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr index 0123e617c4f46..99e7c0b361663 100644 --- a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr +++ b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -6,6 +6,8 @@ LL | | "abc" LL | | }; | |______^ expected `&str`, found struct `String` | + = note: expected reference `&str` + found struct `String` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr index 05d8fcd3ed64b..008a3d2ce3c49 100644 --- a/src/test/ui/suggestions/format-borrow.stderr +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -7,6 +7,9 @@ LL | let a: String = &String::from("a"); | | expected struct `String`, found `&String` | | help: consider removing the borrow: `String::from("a")` | expected due to this + | + = note: expected struct `String` + found reference `&String` error[E0308]: mismatched types --> $DIR/format-borrow.rs:4:21 @@ -17,6 +20,9 @@ LL | let b: String = &format!("b"); | | expected struct `String`, found `&String` | | help: consider removing the borrow: `format!("b")` | expected due to this + | + = note: expected struct `String` + found reference `&String` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr index ece784de3e2a1..702a89c4b56d2 100644 --- a/src/test/ui/suggestions/issue-52820.stderr +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -6,6 +6,9 @@ LL | guts, | | | expected struct `String`, found `&str` | help: try using a conversion method: `guts: guts.to_string()` + | + = note: expected struct `String` + found reference `&str` error[E0308]: mismatched types --> $DIR/issue-52820.rs:10:17 @@ -15,6 +18,9 @@ LL | brains: guts.clone(), | | | expected struct `String`, found `&str` | help: try using a conversion method: `guts.to_string()` + | + = note: expected struct `String` + found reference `&str` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-59819.stderr b/src/test/ui/suggestions/issue-59819.stderr index 43e0016ee20da..75af75cec0e33 100644 --- a/src/test/ui/suggestions/issue-59819.stderr +++ b/src/test/ui/suggestions/issue-59819.stderr @@ -27,6 +27,9 @@ LL | let g: String = f; | | expected struct `String`, found struct `Bar` | | help: try using a conversion method: `f.to_string()` | expected due to this + | + = note: expected struct `String` + found struct `Bar` error: aborting due to 3 previous errors diff --git a/src/test/ui/switched-expectations.stderr b/src/test/ui/switched-expectations.stderr index 82fea0f14bd29..29a17639c04e2 100644 --- a/src/test/ui/switched-expectations.stderr +++ b/src/test/ui/switched-expectations.stderr @@ -3,6 +3,9 @@ error[E0308]: mismatched types | LL | let ref string: String = var; | ^^^ expected struct `String`, found `i32` + | + = note: expected struct `String` + found type `i32` error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-67971.stderr b/src/test/ui/typeck/issue-67971.stderr index 5d07f9cc748ea..81b7a2d08047a 100644 --- a/src/test/ui/typeck/issue-67971.stderr +++ b/src/test/ui/typeck/issue-67971.stderr @@ -11,6 +11,9 @@ LL | fn foo(ctx: &mut S) -> String { | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected struct `String` + found unit type `()` error: aborting due to 2 previous errors From 83ae028d6ee7a918d01328fb3220a7a40143c2e4 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sat, 28 Nov 2020 11:44:42 +0100 Subject: [PATCH 2/3] Add custom allocator support for `CString` --- library/std/src/ffi/c_str.rs | 241 +++++++++++++++++++++++------------ 1 file changed, 157 insertions(+), 84 deletions(-) diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 60b642a6dba44..228a22d84c61c 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -3,11 +3,13 @@ #[cfg(test)] mod tests; +use crate::alloc::{AllocRef, Global}; use crate::ascii; use crate::borrow::{Borrow, Cow}; use crate::cmp::Ordering; use crate::error::Error; use crate::fmt::{self, Write}; +use crate::hash; use crate::io; use crate::mem; use crate::memchr; @@ -109,14 +111,14 @@ use crate::sys; /// documentation of `CString` before use, as improper ownership management /// of `CString` instances can lead to invalid memory accesses, memory leaks, /// and other memory errors. -#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] +#[derive(PartialEq, PartialOrd, Eq, Ord, Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")] #[stable(feature = "rust1", since = "1.0.0")] -pub struct CString { +pub struct CString<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { // Invariant 1: the slice ends with a zero byte and has a length of at least one. // Invariant 2: the slice contains only one zero byte. // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. - inner: Box<[u8]>, + inner: Box<[u8], A>, } /// Representation of a borrowed C string. @@ -219,7 +221,7 @@ pub struct CStr { /// ``` #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct NulError(usize, Vec); +pub struct NulError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global>(usize, Vec); /// An error indicating that a nul byte was not in the expected position. /// @@ -258,11 +260,11 @@ pub struct FromBytesWithNulError { /// /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err(); /// ``` -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] -pub struct FromVecWithNulError { +pub struct FromVecWithNulError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { error_kind: FromBytesWithNulErrorKind, - bytes: Vec, + bytes: Vec, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -281,7 +283,7 @@ impl FromBytesWithNulError { } #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] -impl FromVecWithNulError { +impl FromVecWithNulError { /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`]. /// /// # Examples @@ -324,7 +326,7 @@ impl FromVecWithNulError { /// /// assert_eq!(bytes, value.unwrap_err().into_bytes()); /// ``` - pub fn into_bytes(self) -> Vec { + pub fn into_bytes(self) -> Vec { self.bytes } } @@ -337,10 +339,10 @@ impl FromVecWithNulError { /// /// This `struct` is created by [`CString::into_string()`]. See /// its documentation for more. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] #[stable(feature = "cstring_into", since = "1.7.0")] -pub struct IntoStringError { - inner: CString, +pub struct IntoStringError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { + inner: CString, error: Utf8Error, } @@ -373,7 +375,7 @@ impl CString { /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as /// the position of the nul byte. #[stable(feature = "rust1", since = "1.0.0")] - pub fn new>>(t: T) -> Result { + pub fn new>>(t: T) -> Result { trait SpecIntoVec { fn into_vec(self) -> Vec; } @@ -401,10 +403,70 @@ impl CString { Self::_new(SpecIntoVec::into_vec(t)) } - fn _new(bytes: Vec) -> Result { + /// Retakes ownership of a `CString` that was transferred to C via + /// [`CString::into_raw`]. + /// + /// Additionally, the length of the string will be recalculated from the pointer. + /// + /// # Safety + /// + /// This should only ever be called with a pointer that was earlier + /// obtained by calling [`CString::into_raw`]. Other usage (e.g., trying to take + /// ownership of a string that was allocated by foreign code) is likely to lead + /// to undefined behavior or allocator corruption. + /// + /// It should be noted that the length isn't just "recomputed," but that + /// the recomputed length must match the original length from the + /// [`CString::into_raw`] call. This means the [`CString::into_raw`]/`from_raw` + /// methods should not be used when passing the string to C functions that can + /// modify the string's length. + /// + /// > **Note:** If you need to borrow a string that was allocated by + /// > foreign code, use [`CStr`]. If you need to take ownership of + /// > a string that was allocated by foreign code, you will need to + /// > make your own provisions for freeing it appropriately, likely + /// > with the foreign code's API to do that. + /// + /// # Examples + /// + /// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake + /// ownership with `from_raw`: + /// + /// ```ignore (extern-declaration) + /// use std::ffi::CString; + /// use std::os::raw::c_char; + /// + /// extern { + /// fn some_extern_function(s: *mut c_char); + /// } + /// + /// let c_string = CString::new("Hello!").expect("CString::new failed"); + /// let raw = c_string.into_raw(); + /// unsafe { + /// some_extern_function(raw); + /// let c_string = CString::from_raw(raw); + /// } + /// ``` + #[stable(feature = "cstr_memory", since = "1.4.0")] + pub unsafe fn from_raw(ptr: *mut c_char) -> Self { + // SAFETY: This is called with a pointer that was obtained from a call + // to `CString::into_raw` and the length has not been modified. As such, + // we know there is a NUL byte (and only one) at the end and that the + // information about the size of the allocation is correct on Rust's + // side. + unsafe { + let len = sys::strlen(ptr) + 1; // Including the NUL byte + let slice = slice::from_raw_parts_mut(ptr, len as usize); + CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } + } + } +} + +impl CString { + fn _new(bytes: Vec) -> Result> { match memchr::memchr(0, &bytes) { Some(i) => Err(NulError(i, bytes)), - None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + None => Ok(unsafe { Self::from_vec_unchecked(bytes) }), } } @@ -426,10 +488,10 @@ impl CString { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + pub unsafe fn from_vec_unchecked(mut v: Vec) -> Self { v.reserve_exact(1); v.push(0); - CString { inner: v.into_boxed_slice() } + Self { inner: v.into_boxed_slice() } } /// Retakes ownership of a `CString` that was transferred to C via @@ -455,29 +517,8 @@ impl CString { /// > a string that was allocated by foreign code, you will need to /// > make your own provisions for freeing it appropriately, likely /// > with the foreign code's API to do that. - /// - /// # Examples - /// - /// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake - /// ownership with `from_raw`: - /// - /// ```ignore (extern-declaration) - /// use std::ffi::CString; - /// use std::os::raw::c_char; - /// - /// extern { - /// fn some_extern_function(s: *mut c_char); - /// } - /// - /// let c_string = CString::new("Hello!").expect("CString::new failed"); - /// let raw = c_string.into_raw(); - /// unsafe { - /// some_extern_function(raw); - /// let c_string = CString::from_raw(raw); - /// } - /// ``` #[stable(feature = "cstr_memory", since = "1.4.0")] - pub unsafe fn from_raw(ptr: *mut c_char) -> CString { + pub unsafe fn from_raw_in(ptr: *mut c_char, alloc: A) -> Self { // SAFETY: This is called with a pointer that was obtained from a call // to `CString::into_raw` and the length has not been modified. As such, // we know there is a NUL byte (and only one) at the end and that the @@ -486,7 +527,7 @@ impl CString { unsafe { let len = sys::strlen(ptr) + 1; // Including the NUL byte let slice = slice::from_raw_parts_mut(ptr, len as usize); - CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } + CString { inner: Box::from_raw_in(slice as *mut [c_char] as *mut [u8], alloc) } } } @@ -549,7 +590,7 @@ impl CString { /// ``` #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_string(self) -> Result { + pub fn into_string(self) -> Result, IntoStringError> { String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { error: e.utf8_error(), inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, @@ -572,7 +613,7 @@ impl CString { /// assert_eq!(bytes, vec![b'f', b'o', b'o']); /// ``` #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_bytes(self) -> Vec { + pub fn into_bytes(self) -> Vec { let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); @@ -592,7 +633,7 @@ impl CString { /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); /// ``` #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_bytes_with_nul(self) -> Vec { + pub fn into_bytes_with_nul(self) -> Vec { self.into_inner().into_vec() } @@ -667,12 +708,13 @@ impl CString { /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` #[stable(feature = "into_boxed_c_str", since = "1.20.0")] - pub fn into_boxed_c_str(self) -> Box { - unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) } + pub fn into_boxed_c_str(self) -> Box { + let (s, alloc) = Box::into_raw_with_alloc(self.into_inner()); + unsafe { Box::from_raw_in(s as *mut CStr, alloc) } } /// Bypass "move out of struct which implements [`Drop`] trait" restriction. - fn into_inner(self) -> Box<[u8]> { + fn into_inner(self) -> Box<[u8], A> { // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)` // so we use `ManuallyDrop` to ensure `self` is not dropped. // Then we can return the box directly without invalidating it. @@ -700,7 +742,7 @@ impl CString { /// ); /// ``` #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] - pub unsafe fn from_vec_with_nul_unchecked(v: Vec) -> Self { + pub unsafe fn from_vec_with_nul_unchecked(v: Vec) -> Self { Self { inner: v.into_boxed_slice() } } @@ -740,7 +782,7 @@ impl CString { /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err(); /// ``` #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] - pub fn from_vec_with_nul(v: Vec) -> Result { + pub fn from_vec_with_nul(v: Vec) -> Result> { let nul_pos = memchr::memchr(0, &v); match nul_pos { Some(nul_pos) if nul_pos + 1 == v.len() => { @@ -764,7 +806,7 @@ impl CString { // memory-unsafe code from working by accident. Inline // to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] -impl Drop for CString { +impl Drop for CString { #[inline] fn drop(&mut self) { unsafe { @@ -774,7 +816,7 @@ impl Drop for CString { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for CString { +impl ops::Deref for CString { type Target = CStr; #[inline] @@ -784,19 +826,19 @@ impl ops::Deref for CString { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for CString { +impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "cstring_into", since = "1.7.0")] -impl From for Vec { +impl From> for Vec { /// Converts a [`CString`] into a [`Vec`]``. /// /// The conversion consumes the [`CString`], and removes the terminating NUL byte. #[inline] - fn from(s: CString) -> Vec { + fn from(s: CString) -> Self { s.into_bytes() } } @@ -829,8 +871,16 @@ impl Default for CString { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for CString { + #[inline] + fn hash(&self, hasher: &mut H) { + self.inner.hash(hasher) + } +} + #[stable(feature = "cstr_borrow", since = "1.3.0")] -impl Borrow for CString { +impl Borrow for CString { #[inline] fn borrow(&self) -> &CStr { self @@ -865,28 +915,29 @@ impl From> for Box { } #[stable(feature = "c_string_from_box", since = "1.18.0")] -impl From> for CString { +impl From> for CString { /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. #[inline] - fn from(s: Box) -> CString { + fn from(s: Box) -> Self { s.into_c_string() } } #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] -impl From> for CString { +impl From> for CString { /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without /// copying nor checking for inner null bytes. #[inline] - fn from(v: Vec) -> CString { + fn from(v: Vec) -> Self { unsafe { // Transmute `Vec` to `Vec`. - let v: Vec = { + let v: Vec = { // SAFETY: // - transmuting between `NonZeroU8` and `u8` is sound; // - `alloc::Layout == alloc::Layout`. - let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); - Vec::from_raw_parts(ptr.cast::(), len, cap) + let (ptr, len, cap, alloc): (*mut NonZeroU8, _, _, _) = + Vec::into_raw_parts_with_alloc(v); + Vec::from_raw_parts_in(ptr.cast::(), len, cap, alloc) }; // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. @@ -896,18 +947,20 @@ impl From> for CString { } #[stable(feature = "more_box_slice_clone", since = "1.29.0")] -impl Clone for Box { +impl Clone for Box { #[inline] fn clone(&self) -> Self { - (**self).into() + let alloc = Box::alloc_ref(self).clone(); + // SAFETY: vector comes from `CStr` so it's valid + unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec_in(alloc)).into_boxed_c_str() } } } #[stable(feature = "box_from_c_string", since = "1.20.0")] -impl From for Box { +impl From> for Box { /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. #[inline] - fn from(s: CString) -> Box { + fn from(s: CString) -> Self { s.into_boxed_c_str() } } @@ -915,7 +968,7 @@ impl From for Box { #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From for Cow<'a, CStr> { #[inline] - fn from(s: CString) -> Cow<'a, CStr> { + fn from(s: CString) -> Self { Cow::Owned(s) } } @@ -923,7 +976,7 @@ impl<'a> From for Cow<'a, CStr> { #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CStr> for Cow<'a, CStr> { #[inline] - fn from(s: &'a CStr) -> Cow<'a, CStr> { + fn from(s: &'a CStr) -> Self { Cow::Borrowed(s) } } @@ -931,7 +984,7 @@ impl<'a> From<&'a CStr> for Cow<'a, CStr> { #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CString> for Cow<'a, CStr> { #[inline] - fn from(s: &'a CString) -> Cow<'a, CStr> { + fn from(s: &'a CString) -> Self { Cow::Borrowed(s.as_c_str()) } } @@ -940,7 +993,7 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { impl From for Arc { /// Converts a [`CString`] into a [`Arc`]`` without copying or allocating. #[inline] - fn from(s: CString) -> Arc { + fn from(s: CString) -> Self { let arc: Arc<[u8]> = Arc::from(s.into_inner()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } } @@ -949,7 +1002,7 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Arc { #[inline] - fn from(s: &CStr) -> Arc { + fn from(s: &CStr) -> Self { let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } } @@ -959,7 +1012,7 @@ impl From<&CStr> for Arc { impl From for Rc { /// Converts a [`CString`] into a [`Rc`]`` without copying or allocating. #[inline] - fn from(s: CString) -> Rc { + fn from(s: CString) -> Self { let rc: Rc<[u8]> = Rc::from(s.into_inner()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } } @@ -968,7 +1021,7 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Rc { #[inline] - fn from(s: &CStr) -> Rc { + fn from(s: &CStr) -> Self { let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } } @@ -976,7 +1029,7 @@ impl From<&CStr> for Rc { #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { - fn default() -> Box { + fn default() -> Self { let boxed: Box<[u8]> = Box::from([0]); unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } } @@ -1068,10 +1121,20 @@ impl fmt::Display for FromBytesWithNulError { } #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] -impl Error for FromVecWithNulError {} +impl Error for FromVecWithNulError {} + +#[stable(feature = "cstring_into", since = "1.7.0")] +impl fmt::Debug for FromVecWithNulError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FromVecWithNulError") + .field("error_kind", &self.error_kind) + .field("bytes", &self.bytes) + .finish() + } +} #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] -impl fmt::Display for FromVecWithNulError { +impl fmt::Display for FromVecWithNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.error_kind { FromBytesWithNulErrorKind::InteriorNul(pos) => { @@ -1084,11 +1147,11 @@ impl fmt::Display for FromVecWithNulError { } } -impl IntoStringError { +impl IntoStringError { /// Consumes this error, returning original [`CString`] which generated the /// error. #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_cstring(self) -> CString { + pub fn into_cstring(self) -> CString { self.inner } @@ -1100,7 +1163,7 @@ impl IntoStringError { } #[stable(feature = "cstring_into", since = "1.7.0")] -impl Error for IntoStringError { +impl Error for IntoStringError { #[allow(deprecated)] fn description(&self) -> &str { "C string contained non-utf8 bytes" @@ -1112,7 +1175,17 @@ impl Error for IntoStringError { } #[stable(feature = "cstring_into", since = "1.7.0")] -impl fmt::Display for IntoStringError { +impl fmt::Debug for IntoStringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IntoStringError") + .field("inner", &self.inner) + .field("error", &self.error) + .finish() + } +} + +#[stable(feature = "cstring_into", since = "1.7.0")] +impl fmt::Display for IntoStringError { #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.description().fmt(f) @@ -1433,9 +1506,9 @@ impl CStr { /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed")); /// ``` #[stable(feature = "into_boxed_c_str", since = "1.20.0")] - pub fn into_c_string(self: Box) -> CString { - let raw = Box::into_raw(self) as *mut [u8]; - CString { inner: unsafe { Box::from_raw(raw) } } + pub fn into_c_string(self: Box) -> CString { + let (raw, alloc) = Box::into_raw_with_alloc(self); + CString { inner: unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } } } } @@ -1483,7 +1556,7 @@ impl From<&CStr> for CString { } #[stable(feature = "cstring_asref", since = "1.7.0")] -impl ops::Index for CString { +impl ops::Index for CString { type Output = CStr; #[inline] @@ -1522,7 +1595,7 @@ impl AsRef for CStr { } #[stable(feature = "cstring_asref", since = "1.7.0")] -impl AsRef for CString { +impl AsRef for CString { #[inline] fn as_ref(&self) -> &CStr { self From 61ce8e0ef98af5b24e1a53fc21edcfae9069111b Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sat, 28 Nov 2020 11:53:53 +0100 Subject: [PATCH 3/3] Satisfy tidy --- library/std/src/ffi/c_str.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 228a22d84c61c..24a0f164cd971 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -221,7 +221,10 @@ pub struct CStr { /// ``` #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct NulError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global>(usize, Vec); +pub struct NulError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global>( + usize, + Vec, +); /// An error indicating that a nul byte was not in the expected position. /// @@ -262,7 +265,9 @@ pub struct FromBytesWithNulError { /// ``` #[derive(Clone, PartialEq, Eq)] #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] -pub struct FromVecWithNulError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { +pub struct FromVecWithNulError< + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +> { error_kind: FromBytesWithNulErrorKind, bytes: Vec, } @@ -341,7 +346,9 @@ impl FromVecWithNulError { /// its documentation for more. #[derive(Clone, PartialEq, Eq)] #[stable(feature = "cstring_into", since = "1.7.0")] -pub struct IntoStringError<#[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> { +pub struct IntoStringError< + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +> { inner: CString, error: Utf8Error, }