Implied,
Input,
Into,
+ IntoFuture,
IntoIterator,
IoRead,
IoWrite,
asm_const,
asm_experimental_arch,
asm_sym,
+ asm_unwind,
assert,
assert_inhabited,
assert_macro,
compiler_builtins,
compiler_fence,
concat,
+ concat_bytes,
concat_idents,
conservative_impl_trait,
console,
core_panic_macro,
cosf32,
cosf64,
+ count,
cr,
crate_id,
crate_in_paths,
fdiv_fast,
feature,
fence,
+ ferris: "🦀",
fetch_update,
ffi,
ffi_const,
inout,
instruction_set,
intel,
+ into_future,
into_iter,
intra_doc_pointers,
intrinsics,
literal,
llvm_asm,
load,
+ loaded_from_disk,
local,
local_inner_macros,
log10f32,
maxnumf32,
maxnumf64,
may_dangle,
+ may_unwind,
maybe_uninit,
maybe_uninit_uninit,
maybe_uninit_zeroed,
reg64,
reg_abcd,
reg_byte,
+ reg_iw,
reg_nonzero,
- reg_thumb,
+ reg_pair,
+ reg_ptr,
+ reg_upper,
register_attr,
register_tool,
relaxed_adts,
unmarked_api,
unpin,
unreachable,
+ unreachable_2015,
+ unreachable_2015_macro,
+ unreachable_2021,
+ unreachable_2021_macro,
unreachable_code,
+ unreachable_display,
+ unreachable_macro,
unrestricted_attribute_tokens,
unsafe_block_in_unsafe_fn,
unsafe_cell,
Ident::new(self.name, self.span.normalize_to_macro_rules())
}
- /// Convert the name to a `SymbolStr`. This is a slowish operation because
- /// it requires locking the symbol interner.
- pub fn as_str(self) -> SymbolStr {
+ /// Access the underlying string. This is a slowish operation because it
+ /// requires locking the symbol interner.
+ ///
+ /// Note that the lifetime of the return value is a lie. See
+ /// `Symbol::as_str()` for details.
+ pub fn as_str(&self) -> &str {
self.name.as_str()
}
}
with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
}
- /// Convert to a `SymbolStr`. This is a slowish operation because it
+ /// Access the underlying string. This is a slowish operation because it
/// requires locking the symbol interner.
- pub fn as_str(self) -> SymbolStr {
- with_session_globals(|session_globals| {
- let symbol_str = session_globals.symbol_interner.get(self);
- unsafe { SymbolStr { string: std::mem::transmute::<&str, &str>(symbol_str) } }
+ ///
+ /// Note that the lifetime of the return value is a lie. It's not the same
+ /// as `&self`, but actually tied to the lifetime of the underlying
+ /// interner. Interners are long-lived, and there are very few of them, and
+ /// this function is typically used for short-lived things, so in practice
+ /// it works out ok.
+ pub fn as_str(&self) -> &str {
+ with_session_globals(|session_globals| unsafe {
+ std::mem::transmute::<&str, &str>(session_globals.symbol_interner.get(*self))
})
}
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.as_str(), f)
+ fmt::Debug::fmt(self.as_str(), f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.as_str(), f)
+ fmt::Display::fmt(self.as_str(), f)
}
}
impl<S: Encoder> Encodable<S> for Symbol {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_str(&self.as_str())
+ s.emit_str(self.as_str())
}
}
}
impl<CTX> ToStableHashKey<CTX> for Symbol {
- type KeyType = SymbolStr;
-
+ type KeyType = String;
#[inline]
- fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr {
- self.as_str()
+ fn to_stable_hash_key(&self, _: &CTX) -> String {
+ self.as_str().to_string()
}
}
// found that to regress performance up to 2% in some cases. This might be
// revisited after further improvements to `indexmap`.
//
-// This type is private to prevent accidentally constructing more than one `Interner` on the same
-// thread, which makes it easy to mixup `Symbol`s between `Interner`s.
+// This type is private to prevent accidentally constructing more than one
+// `Interner` on the same thread, which makes it easy to mixup `Symbol`s
+// between `Interner`s.
#[derive(Default)]
struct InternerInner {
arena: DroplessArena,
let name = Symbol::new(inner.strings.len() as u32);
- // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
- // UTF-8.
+ // 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())) };
- // It is safe to extend the arena allocation to `'static` because we only access
- // these while the arena is still alive.
+
+ // SAFETY: we can extend the arena allocation to `'static` because we
+ // only access these while the arena is still alive.
let string: &'static str = unsafe { &*(string as *const str) };
inner.strings.push(string);
+
+ // This second hash table lookup can be avoided by using `RawEntryMut`,
+ // but this code path isn't hot enough for it to be worth it. See
+ // #91445 for details.
inner.names.insert(string, name);
name
}
self.name.can_be_raw() && self.is_reserved()
}
}
-
-/// An alternative to [`Symbol`], useful when the chars within the symbol need to
-/// be accessed. It deliberately has limited functionality and should only be
-/// used for temporary values.
-///
-/// Because the interner outlives any thread which uses this type, we can
-/// safely treat `string` which points to interner data, as an immortal string,
-/// as long as this type never crosses between threads.
-//
-// FIXME: ensure that the interner outlives any thread which uses `SymbolStr`,
-// by creating a new thread right after constructing the interner.
-#[derive(Clone, Eq, PartialOrd, Ord)]
-pub struct SymbolStr {
- string: &'static str,
-}
-
-// This impl allows a `SymbolStr` to be directly equated with a `String` or
-// `&str`.
-impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for SymbolStr {
- fn eq(&self, other: &T) -> bool {
- self.string == other.deref()
- }
-}
-
-impl !Send for SymbolStr {}
-impl !Sync for SymbolStr {}
-
-/// This impl means that if `ss` is a `SymbolStr`:
-/// - `*ss` is a `str`;
-/// - `&*ss` is a `&str` (and `match &*ss { ... }` is a common pattern).
-/// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a
-/// function expecting a `&str`.
-impl std::ops::Deref for SymbolStr {
- type Target = str;
- #[inline]
- fn deref(&self) -> &str {
- self.string
- }
-}
-
-impl fmt::Debug for SymbolStr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(self.string, f)
- }
-}
-
-impl fmt::Display for SymbolStr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self.string, f)
- }
-}
-
-impl<CTX> HashStable<CTX> for SymbolStr {
- #[inline]
- fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
- self.string.hash_stable(hcx, hasher)
- }
-}
-
-impl<CTX> ToStableHashKey<CTX> for SymbolStr {
- type KeyType = SymbolStr;
-
- #[inline]
- fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr {
- self.clone()
- }
-}