rustc: replace interior_unsafe with a Freeze trait.
This commit is contained in:
parent
3f5c311dc1
commit
6563374ed2
@ -16,6 +16,7 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use cell::UnsafeCell;
|
||||
use cmp;
|
||||
use hash::Hash;
|
||||
use hash::Hasher;
|
||||
@ -553,3 +554,19 @@ mod impls {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
|
||||
}
|
||||
|
||||
/// Compiler-internal trait used to determine whether a type contains
|
||||
/// any `UnsafeCell` internally, but not through an indirection.
|
||||
/// This affects, for example, whether a `static` of that type is
|
||||
/// placed in read-only static memory or writable static memory.
|
||||
#[cfg_attr(not(stage0), lang = "freeze")]
|
||||
unsafe trait Freeze {}
|
||||
|
||||
unsafe impl Freeze for .. {}
|
||||
|
||||
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for *const T {}
|
||||
unsafe impl<T: ?Sized> Freeze for *mut T {}
|
||||
unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
|
||||
unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
|
||||
|
@ -274,6 +274,7 @@ language_item_table! {
|
||||
UnsizeTraitLangItem, "unsize", unsize_trait;
|
||||
CopyTraitLangItem, "copy", copy_trait;
|
||||
SyncTraitLangItem, "sync", sync_trait;
|
||||
FreezeTraitLangItem, "freeze", freeze_trait;
|
||||
|
||||
DropTraitLangItem, "drop", drop_trait;
|
||||
|
||||
|
@ -24,8 +24,7 @@ bitflags! {
|
||||
/// easier for me (nmatsakis) to think about what is contained within
|
||||
/// a type than to think about what is *not* contained within a type.
|
||||
flags TypeContents: u8 {
|
||||
const INTERIOR_UNSAFE = 0b01,
|
||||
const OWNS_DTOR = 0b10,
|
||||
const OWNS_DTOR = 0b1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,10 +33,6 @@ impl TypeContents {
|
||||
if cond {*self} else {TypeContents::empty()}
|
||||
}
|
||||
|
||||
pub fn interior_unsafe(&self) -> bool {
|
||||
self.intersects(TypeContents::INTERIOR_UNSAFE)
|
||||
}
|
||||
|
||||
pub fn needs_drop(&self, _: TyCtxt) -> bool {
|
||||
self.intersects(TypeContents::OWNS_DTOR)
|
||||
}
|
||||
@ -124,17 +119,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
// unions don't have destructors regardless of the child types
|
||||
- TypeContents::OWNS_DTOR.when(def.is_union())
|
||||
| TypeContents::OWNS_DTOR.when(def.has_dtor(tcx))
|
||||
| TypeContents::INTERIOR_UNSAFE.when(
|
||||
Some(def.did) == tcx.lang_items.unsafe_cell_type())
|
||||
}
|
||||
|
||||
|
||||
ty::TyDynamic(..) |
|
||||
ty::TyProjection(..) |
|
||||
ty::TyParam(_) |
|
||||
ty::TyAnon(..) => {
|
||||
TypeContents::INTERIOR_UNSAFE | TypeContents::OWNS_DTOR
|
||||
}
|
||||
ty::TyAnon(..) => TypeContents::OWNS_DTOR,
|
||||
|
||||
ty::TyInfer(_) |
|
||||
ty::TyError => {
|
||||
|
@ -425,6 +425,8 @@ bitflags! {
|
||||
const IS_SIZED = 1 << 17,
|
||||
const MOVENESS_CACHED = 1 << 18,
|
||||
const MOVES_BY_DEFAULT = 1 << 19,
|
||||
const FREEZENESS_CACHED = 1 << 20,
|
||||
const IS_FREEZE = 1 << 21,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1181,6 +1183,9 @@ pub struct ParameterEnvironment<'tcx> {
|
||||
|
||||
/// A cache for `type_is_sized`
|
||||
pub is_sized_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
|
||||
|
||||
/// A cache for `type_is_freeze`
|
||||
pub is_freeze_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
||||
@ -1195,6 +1200,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
||||
free_id_outlive: self.free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2531,6 +2537,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2603,6 +2610,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FxHashMap()),
|
||||
is_sized_cache: RefCell::new(FxHashMap()),
|
||||
is_freeze_cache: RefCell::new(FxHashMap()),
|
||||
};
|
||||
|
||||
let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
|
||||
|
@ -655,6 +655,50 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns `true` if and only if there are no `UnsafeCell`s
|
||||
/// nested within the type (ignoring `PhantomData` or pointers).
|
||||
#[inline]
|
||||
pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
span: Span) -> bool
|
||||
{
|
||||
if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) {
|
||||
return self.flags.get().intersects(TypeFlags::IS_FREEZE);
|
||||
}
|
||||
|
||||
self.is_freeze_uncached(tcx, param_env, span)
|
||||
}
|
||||
|
||||
fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
span: Span) -> bool {
|
||||
assert!(!self.needs_infer());
|
||||
|
||||
// Fast-path for primitive types
|
||||
let result = match self.sty {
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
|
||||
TyStr | TyNever => Some(true),
|
||||
|
||||
TyArray(..) | TySlice(_) |
|
||||
TyTuple(..) | TyClosure(..) | TyAdt(..) |
|
||||
TyDynamic(..) | TyProjection(..) | TyParam(..) |
|
||||
TyInfer(..) | TyAnon(..) | TyError => None
|
||||
}.unwrap_or_else(|| {
|
||||
self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem),
|
||||
¶m_env.is_freeze_cache, span) });
|
||||
|
||||
if !self.has_param_types() && !self.has_self_ty() {
|
||||
self.flags.set(self.flags.get() | if result {
|
||||
TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE
|
||||
} else {
|
||||
TypeFlags::FREEZENESS_CACHED
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
|
||||
-> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
|
@ -80,7 +80,7 @@ impl<'a, 'tcx> Qualif {
|
||||
fn restrict(&mut self, ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>) {
|
||||
if !ty.type_contents(tcx).interior_unsafe() {
|
||||
if ty.is_freeze(tcx, param_env, DUMMY_SP) {
|
||||
*self = *self - Qualif::MUTABLE_INTERIOR;
|
||||
}
|
||||
if !tcx.type_needs_drop_given_env(ty, param_env) {
|
||||
|
@ -46,7 +46,7 @@ use rustc::lint::builtin::CONST_ERR;
|
||||
|
||||
use rustc::hir::{self, PatKind, RangeEnd};
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -85,7 +85,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
||||
|
||||
// Adds the worst effect out of all the values of one type.
|
||||
fn add_type(&mut self, ty: Ty<'gcx>) {
|
||||
if ty.type_contents(self.tcx).interior_unsafe() {
|
||||
if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) {
|
||||
self.promotable = false;
|
||||
}
|
||||
|
||||
|
@ -746,13 +746,13 @@ impl<'a, 'tcx> FnType<'tcx> {
|
||||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
|
||||
// both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
|
||||
// on memory dependencies rather than pointer equality
|
||||
let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
|
||||
let is_freeze = ccx.shared().type_is_freeze(mt.ty);
|
||||
|
||||
if mt.mutbl != hir::MutMutable && !interior_unsafe {
|
||||
if mt.mutbl != hir::MutMutable && is_freeze {
|
||||
arg.attrs.set(ArgAttribute::NoAlias);
|
||||
}
|
||||
|
||||
if mt.mutbl == hir::MutImmutable && !interior_unsafe {
|
||||
if mt.mutbl == hir::MutImmutable && is_freeze {
|
||||
arg.attrs.set(ArgAttribute::ReadOnly);
|
||||
}
|
||||
|
||||
|
@ -261,8 +261,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// As an optimization, all shared statics which do not have interior
|
||||
// mutability are placed into read-only memory.
|
||||
if m != hir::MutMutable {
|
||||
let tcontents = ty.type_contents(ccx.tcx());
|
||||
if !tcontents.interior_unsafe() {
|
||||
if ccx.shared().type_is_freeze(ty) {
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
||||
}
|
||||
}
|
||||
|
@ -399,6 +399,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
||||
ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
|
||||
&self.exported_symbols
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user