diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index c0d292cd20886..0241bb53c639c 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -368,21 +368,17 @@ impl str { pub fn to_lowercase(&self) -> String { let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase); - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - // Safety: We have written only valid ASCII to our vec let mut s = unsafe { String::from_utf8_unchecked(out) }; - for (i, c) in rest[..].char_indices() { + for (i, c) in self.char_indices().skip(s.len()) { if c == 'Σ' { // Σ maps to σ, except at the end of a word where it maps to ς. // This is the only conditional (contextual) but language-independent mapping // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - map_uppercase_sigma(rest, i, &mut s) + s.push(map_uppercase_sigma(&self, i)); } else { match conversions::to_lower(c) { [a, '\0', _] => s.push(a), @@ -400,13 +396,13 @@ impl str { } return s; - fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) { + fn map_uppercase_sigma(from: &str, i: usize) -> char { // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 // for the definition of `Final_Sigma`. debug_assert!('Σ'.len_utf8() == 2); let is_word_final = case_ignorable_then_cased(from[..i].chars().rev()) && !case_ignorable_then_cased(from[i + 2..].chars()); - to.push_str(if is_word_final { "ς" } else { "σ" }); + if is_word_final { 'ς' } else { 'σ' } } fn case_ignorable_then_cased>(iter: I) -> bool { diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index df8a260624a28..0078f5eaa3d2b 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1848,6 +1848,9 @@ fn to_lowercase() { assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); + // https://github.com/rust-lang/rust/issues/124714 + assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + // a really long string that has it's lowercase form // even longer. this tests that implementations don't assume // an incorrect upper bound on allocations