diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 756af7269f2..621516af9c0 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -484,6 +484,20 @@ pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] } } + /// Allocates a string slice that is copied into the `DroplessArena`, returning a + /// reference to it. Will panic if passed an empty string. + /// + /// Panics: + /// + /// - Zero-length string + #[inline] + pub fn alloc_str(&self, string: &str) -> &str { + let slice = self.alloc_slice(string.as_bytes()); + + // SAFETY: the result has a copy of the same valid UTF-8 bytes. + unsafe { std::str::from_utf8_unchecked(slice) } + } + /// # Safety /// /// The caller must ensure that `mem` is valid for writes up to `size_of::() * len`, and that @@ -655,6 +669,14 @@ pub fn alloc_slice(&self, value: &[T]) -> &mut [T] { self.dropless.alloc_slice(value) } + #[inline] + pub fn alloc_str(&self, string: &str) -> &str { + if string.is_empty() { + return ""; + } + self.dropless.alloc_str(string) + } + #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter, C>( &self, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9feda4d205e..bedb8050e6b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2614,9 +2614,7 @@ pub struct SymbolName<'tcx> { impl<'tcx> SymbolName<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> { - SymbolName { - name: unsafe { str::from_utf8_unchecked(tcx.arena.alloc_slice(name.as_bytes())) }, - } + SymbolName { name: tcx.arena.alloc_str(name) } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d7e822382ef..3190ccaf7b4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2118,11 +2118,7 @@ fn intern(&self, string: &str) -> Symbol { return Symbol::new(idx as u32); } - // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, - // and immediately convert the clone back to `&[u8]`, all because there - // is no `inner.arena.alloc_str()` method. This is clearly safe. - let string: &str = - unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) }; + let string: &str = inner.arena.alloc_str(string); // SAFETY: we can extend the arena allocation to `'static` because we // only access these while the arena is still alive.