Well; strictly speaking it can become part of the type:
#![feature(optin_builtin_traits)]
mod frozen {
use core::{ops::Deref, cell::UnsafeCell, marker::PhantomData};
pub unsafe auto trait Interiorless {}
impl<T: ?Sized> !Interiorless for UnsafeCell<T> {}
unsafe impl<T: ?Sized> Interiorless for PhantomData<T> {}
unsafe impl<T: ?Sized> Interiorless for *const T {}
unsafe impl<T: ?Sized> Interiorless for *mut T {}
unsafe impl<T: ?Sized> Interiorless for &T {}
unsafe impl<T: ?Sized> Interiorless for &mut T {}
pub struct Frozen<T> {
value: T,
}
impl<T> Frozen<T> {
pub fn new(value: T) -> Self {
Self { value }
}
}
impl<T: Interiorless> Deref for Frozen<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
}
The logic of this is that while you may have let mut x = Frozen::new(1);, there are no &mut operations on Frozen<u8> so it is immutable; furthermore, with T: Interiorless interior mutability is forbidden so that avenue is closed as well. What remains are Clone, Copy, and other such "I can recreate T from &T facilities" but that's fine under "immutable".
The usefulness of Frozen is debatable tho.