From 92bf40ffe30832ba459e50d6f51d9e9a1cde9cd2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 5 Dec 2023 17:33:16 -0800 Subject: [PATCH] rustc_arena: add `alloc_str` Two places called `from_utf8_unchecked` for strings from `alloc_slice`, and one's SAFETY comment said this was for lack of `alloc_str` -- so let's just add that instead! --- compiler/rustc_arena/src/lib.rs | 22 ++++++++++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 4 +--- compiler/rustc_span/src/symbol.rs | 6 +----- 3 files changed, 24 insertions(+), 8 deletions(-) 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 @@ impl DroplessArena { } } + /// 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 macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { 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 @@ impl Interner { 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.