about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-04-17 21:18:56 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-04-20 14:39:31 +0300
commit6563374ed2e518ea5fec2b7411dc4331772c46d2 (patch)
tree6211971da9ad119e25d1b2c2e13960c65611a29d /src
parent3f5c311dc1dcb5bfe65d6eecd0dfda04d77c7594 (diff)
downloadrust-6563374ed2e518ea5fec2b7411dc4331772c46d2.tar.gz
rust-6563374ed2e518ea5fec2b7411dc4331772c46d2.zip
rustc: replace interior_unsafe with a Freeze trait.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/marker.rs17
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc/ty/contents.rs14
-rw-r--r--src/librustc/ty/mod.rs8
-rw-r--r--src/librustc/ty/util.rs44
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_passes/consts.rs4
-rw-r--r--src/librustc_trans/abi.rs6
-rw-r--r--src/librustc_trans/consts.rs3
-rw-r--r--src/librustc_trans/context.rs4
10 files changed, 83 insertions, 20 deletions
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 393c01b0105..c0aa650a1e8 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -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 {}
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 5989fa9007c..32dfb63d615 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -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;
 
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index c690795b342..a1cb848213a 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -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 => {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 78d3885bb98..7325235ca7b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -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));
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 5334ee2835d..d43d570397b 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -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),
+                              &param_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>> {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 1313b24fa74..cc7d2562843 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -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) {
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 2c4439f80a2..535c6a7ab9e 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -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;
         }
 
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index c4fdc46d030..e0a75f3caa7 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -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);
                 }
 
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 7a53a03344f..eb3ac309be1 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -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);
             }
         }
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index c3770470bfd..fd9ff17cc64 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -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
     }