diff options
| author | bors <bors@rust-lang.org> | 2021-05-06 04:41:20 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-05-06 04:41:20 +0000 |
| commit | d620ae10709ca3669cda89db8b29afcd9accc188 (patch) | |
| tree | 6c6207c1b91ef951dd965701aa38c88c1feca5da /library/alloc/src/string.rs | |
| parent | bacf770f2983a52f31e3537db5f0fe1ef2eaa874 (diff) | |
| parent | 19be438cda610232be5ca84e08c74925a481c465 (diff) | |
| download | rust-d620ae10709ca3669cda89db8b29afcd9accc188.tar.gz rust-d620ae10709ca3669cda89db8b29afcd9accc188.zip | |
Auto merge of #84266 - QuiltOS:statically-disallow-global-oom-handling, r=Mark-Simulacrum
alloc: Add unstable Cfg feature `no-global_oom_handling For certain sorts of systems, programming, it's deemed essential that all allocation failures be explicitly handled where they occur. For example, see Linus Torvald's opinion in [1]. Merely not calling global panic handlers, or always `try_reserving` first (for vectors), is not deemed good enough, because the mere presence of the global OOM handlers is burdens static analysis. One option for these projects to use rust would just be to skip `alloc`, rolling their own allocation abstractions. But this would, in my opinion be a real shame. `alloc` has a few `try_*` methods already, and we could easily have more. Features like custom allocator support also demonstrate and existing to support diverse use-cases with the same abstractions. A natural way to add such a feature flag would a Cargo feature, but there are currently uncertainties around how std library crate's Cargo features may or not be stable, so to avoid any risk of stabilizing by mistake we are going with a more low-level "raw cfg" token, which cannot be interacted with via Cargo alone. Note also that since there is no notion of "default cfg tokens" outside of Cargo features, we have to invert the condition from `global_oom_handling` to to `not(no_global_oom_handling)`. This breaks the monotonicity that would be important for a Cargo feature (i.e. turning on more features should never break compatibility), but it doesn't matter for raw cfg tokens which are not intended to be "constraint solved" by Cargo or anything else. To support this use-case we create a new feature, "global-oom-handling", on by default, and put the global OOM handler infra and everything else it that depends on it behind it. By default, nothing is changed, but users concerned about global handling can make sure it is disabled, and be confident that all OOM handling is local and explicit. For this first iteration, non-flat collections are outright disabled. `Vec` and `String` don't yet have `try_*` allocation methods, but are kept anyways since they can be oom-safely created "from parts", and we hope to add those `try_` methods in the future. [1]: https://lore.kernel.org/lkml/CAHk-=wh_sNLoz84AUUzuqXEsYH35u=8HV3vK-jbRbJ_B-JjGrg@mail.gmail.com/
Diffstat (limited to 'library/alloc/src/string.rs')
| -rw-r--r-- | library/alloc/src/string.rs | 80 |
1 files changed, 75 insertions, 5 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4aeb3de6592..e6252452470 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -42,20 +42,33 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(no_global_oom_handling))] use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; -use core::iter::{FromIterator, FusedIterator}; +#[cfg(not(no_global_oom_handling))] +use core::iter::FromIterator; +use core::iter::FusedIterator; +#[cfg(not(no_global_oom_handling))] +use core::ops::Add; +#[cfg(not(no_global_oom_handling))] +use core::ops::AddAssign; +#[cfg(not(no_global_oom_handling))] use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; +use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr; use core::slice; -use core::str::{lossy, pattern::Pattern}; +#[cfg(not(no_global_oom_handling))] +use core::str::lossy; +use core::str::pattern::Pattern; +#[cfg(not(no_global_oom_handling))] use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, from_boxed_utf8_unchecked, Chars, FromStr, Utf8Error}; +use crate::str::{self, Chars, Utf8Error}; +#[cfg(not(no_global_oom_handling))] +use crate::str::{from_boxed_utf8_unchecked, FromStr}; use crate::vec::Vec; /// A UTF-8–encoded, growable string. @@ -314,7 +327,8 @@ pub struct String { /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(not(no_global_oom_handling), derive(Clone))] +#[derive(Debug, PartialEq, Eq)] pub struct FromUtf8Error { bytes: Vec<u8>, error: Utf8Error, @@ -403,6 +417,7 @@ impl String { /// // ...but this may make the string reallocate /// s.push('a'); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[doc(alias = "alloc")] #[doc(alias = "malloc")] @@ -535,6 +550,7 @@ impl String { /// /// assert_eq!("Hello �World", output); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks(); @@ -587,6 +603,7 @@ impl String { /// 0xD800, 0x0069, 0x0063]; /// assert!(String::from_utf16(v).is_err()); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> { // This isn't done via collect::<Result<_, _>>() for performance reasons. @@ -626,6 +643,7 @@ impl String { /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"), /// String::from_utf16_lossy(v)); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf16_lossy(v: &[u16]) -> String { @@ -818,6 +836,7 @@ impl String { /// /// assert_eq!("foobar", s); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push_str(&mut self, string: &str) { @@ -885,6 +904,7 @@ impl String { /// // ... doesn't actually increase. /// assert_eq!(10, s.capacity()); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { @@ -932,6 +952,7 @@ impl String { /// // ... doesn't actually increase. /// assert_eq!(10, s.capacity()); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { @@ -1026,6 +1047,7 @@ impl String { /// s.shrink_to_fit(); /// assert_eq!(3, s.capacity()); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { @@ -1053,6 +1075,7 @@ impl String { /// s.shrink_to(0); /// assert!(s.capacity() >= 3); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { @@ -1074,6 +1097,7 @@ impl String { /// /// assert_eq!("abc123", s); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, ch: char) { @@ -1222,6 +1246,7 @@ impl String { /// s.remove_matches("ana"); /// assert_eq!("bna", s); /// ``` + #[cfg(not(no_global_oom_handling))] #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")] pub fn remove_matches<'a, P>(&'a mut self, pat: P) where @@ -1352,6 +1377,7 @@ impl String { /// /// assert_eq!("foo", s); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, idx: usize, ch: char) { @@ -1364,6 +1390,7 @@ impl String { } } + #[cfg(not(no_global_oom_handling))] unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { let len = self.len(); let amt = bytes.len(); @@ -1397,6 +1424,7 @@ impl String { /// /// assert_eq!("foobar", s); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "insert_str", since = "1.16.0")] pub fn insert_str(&mut self, idx: usize, string: &str) { @@ -1502,6 +1530,7 @@ impl String { /// assert_eq!(world, "World!"); /// # } /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "string_split_off", since = "1.16.0")] #[must_use = "use `.truncate()` if you don't need the other half"] @@ -1608,6 +1637,7 @@ impl String { /// s.replace_range(..beta_offset, "Α is capital alpha; "); /// assert_eq!(s, "Α is capital alpha; β is beta"); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "splice", since = "1.27.0")] pub fn replace_range<R>(&mut self, range: R, replace_with: &str) where @@ -1654,6 +1684,7 @@ impl String { /// /// let b = s.into_boxed_str(); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_str", since = "1.4.0")] #[inline] pub fn into_boxed_str(self) -> Box<str> { @@ -1748,6 +1779,7 @@ impl fmt::Display for FromUtf16Error { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { fn clone(&self) -> Self { @@ -1759,6 +1791,7 @@ impl Clone for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<char> for String { fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String { @@ -1768,6 +1801,7 @@ impl FromIterator<char> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "string_from_iter_by_ref", since = "1.17.0")] impl<'a> FromIterator<&'a char> for String { fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String { @@ -1777,6 +1811,7 @@ impl<'a> FromIterator<&'a char> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> FromIterator<&'a str> for String { fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String { @@ -1786,6 +1821,7 @@ impl<'a> FromIterator<&'a str> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_string", since = "1.4.0")] impl FromIterator<String> for String { fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String { @@ -1804,6 +1840,7 @@ impl FromIterator<String> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "box_str2", since = "1.45.0")] impl FromIterator<Box<str>> for String { fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String { @@ -1813,6 +1850,7 @@ impl FromIterator<Box<str>> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "herd_cows", since = "1.19.0")] impl<'a> FromIterator<Cow<'a, str>> for String { fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String { @@ -1832,6 +1870,7 @@ impl<'a> FromIterator<Cow<'a, str>> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Extend<char> for String { fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) { @@ -1852,6 +1891,7 @@ impl Extend<char> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a> Extend<&'a char> for String { fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) { @@ -1869,6 +1909,7 @@ impl<'a> Extend<&'a char> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Extend<&'a str> for String { fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) { @@ -1881,6 +1922,7 @@ impl<'a> Extend<&'a str> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "box_str2", since = "1.45.0")] impl Extend<Box<str>> for String { fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) { @@ -1888,6 +1930,7 @@ impl Extend<Box<str>> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_string", since = "1.4.0")] impl Extend<String> for String { fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) { @@ -1900,6 +1943,7 @@ impl Extend<String> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "herd_cows", since = "1.19.0")] impl<'a> Extend<Cow<'a, str>> for String { fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) { @@ -2001,8 +2045,11 @@ macro_rules! impl_eq { impl_eq! { String, str } impl_eq! { String, &'a str } +#[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, str } +#[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, &'b str } +#[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] @@ -2075,6 +2122,7 @@ impl hash::Hash for String { /// let b = " world"; /// let c = a.to_string() + b; /// ``` +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Add<&str> for String { type Output = String; @@ -2089,6 +2137,7 @@ impl Add<&str> for String { /// Implements the `+=` operator for appending to a `String`. /// /// This has the same behavior as the [`push_str`][String::push_str] method. +#[cfg(not(no_global_oom_handling))] #[stable(feature = "stringaddassign", since = "1.12.0")] impl AddAssign<&str> for String { #[inline] @@ -2221,6 +2270,7 @@ impl ops::DerefMut for String { #[stable(feature = "str_parse_error", since = "1.5.0")] pub type ParseError = core::convert::Infallible; +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for String { type Err = core::convert::Infallible; @@ -2264,6 +2314,7 @@ pub trait ToString { /// if the `Display` implementation returns an error. /// This indicates an incorrect `Display` implementation /// since `fmt::Write for String` never returns an error itself. +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Display + ?Sized> ToString for T { // A common guideline is to not inline generic functions. However, @@ -2280,6 +2331,7 @@ impl<T: fmt::Display + ?Sized> ToString for T { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "char_to_string_specialization", since = "1.46.0")] impl ToString for char { #[inline] @@ -2288,6 +2340,7 @@ impl ToString for char { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "u8_to_string_specialization", since = "1.54.0")] impl ToString for u8 { #[inline] @@ -2307,6 +2360,7 @@ impl ToString for u8 { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "i8_to_string_specialization", since = "1.54.0")] impl ToString for i8 { #[inline] @@ -2329,6 +2383,7 @@ impl ToString for i8 { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "str_to_string_specialization", since = "1.9.0")] impl ToString for str { #[inline] @@ -2337,6 +2392,7 @@ impl ToString for str { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")] impl ToString for Cow<'_, str> { #[inline] @@ -2345,6 +2401,7 @@ impl ToString for Cow<'_, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "string_to_string_specialization", since = "1.17.0")] impl ToString for String { #[inline] @@ -2377,6 +2434,7 @@ impl AsRef<[u8]> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl From<&str> for String { #[inline] @@ -2385,6 +2443,7 @@ impl From<&str> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "from_mut_str_for_string", since = "1.44.0")] impl From<&mut str> for String { /// Converts a `&mut str` into a `String`. @@ -2396,6 +2455,7 @@ impl From<&mut str> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "from_ref_string", since = "1.35.0")] impl From<&String> for String { #[inline] @@ -2427,6 +2487,7 @@ impl From<Box<str>> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_str", since = "1.20.0")] impl From<String> for Box<str> { /// Converts the given `String` to a boxed `str` slice that is owned. @@ -2447,6 +2508,7 @@ impl From<String> for Box<str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From<Cow<'a, str>> for String { fn from(s: Cow<'a, str>) -> String { @@ -2454,6 +2516,7 @@ impl<'a> From<Cow<'a, str>> for String { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Cow<'a, str> { /// Converts a string slice into a Borrowed variant. @@ -2472,6 +2535,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<String> for Cow<'a, str> { /// Converts a String into an Owned variant. @@ -2492,6 +2556,7 @@ impl<'a> From<String> for Cow<'a, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_from_string_ref", since = "1.28.0")] impl<'a> From<&'a String> for Cow<'a, str> { /// Converts a String reference into a Borrowed variant. @@ -2511,6 +2576,7 @@ impl<'a> From<&'a String> for Cow<'a, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator<char> for Cow<'a, str> { fn from_iter<I: IntoIterator<Item = char>>(it: I) -> Cow<'a, str> { @@ -2518,6 +2584,7 @@ impl<'a> FromIterator<char> for Cow<'a, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> { fn from_iter<I: IntoIterator<Item = &'b str>>(it: I) -> Cow<'a, str> { @@ -2525,6 +2592,7 @@ impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator<String> for Cow<'a, str> { fn from_iter<I: IntoIterator<Item = String>>(it: I) -> Cow<'a, str> { @@ -2553,6 +2621,7 @@ impl From<String> for Vec<u8> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { #[inline] @@ -2676,6 +2745,7 @@ impl DoubleEndedIterator for Drain<'_> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Drain<'_> {} +#[cfg(not(no_global_oom_handling))] #[stable(feature = "from_char_for_string", since = "1.46.0")] impl From<char> for String { #[inline] |
