]> git.lizzy.rs Git - rust.git/commitdiff
rustc: replace interior_unsafe with a Freeze trait.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 17 Apr 2017 18:18:56 +0000 (21:18 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 20 Apr 2017 11:39:31 +0000 (14:39 +0300)
src/libcore/marker.rs
src/librustc/middle/lang_items.rs
src/librustc/ty/contents.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_passes/consts.rs
src/librustc_trans/abi.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs

index 393c01b0105c5c63d427e042d27bc46592509607..c0aa650a1e854735b6aca0746e14bae1b65bd360 100644 (file)
@@ -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 @@ unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
     #[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 {}
index 5989fa9007c4446ee177acd71be6de9ed68de0db..32dfb63d6150a5933d13294120e30a459ed4487f 100644 (file)
@@ -274,6 +274,7 @@ pub fn collect_language_items(session: &Session,
     UnsizeTraitLangItem,             "unsize",                  unsize_trait;
     CopyTraitLangItem,               "copy",                    copy_trait;
     SyncTraitLangItem,               "sync",                    sync_trait;
+    FreezeTraitLangItem,             "freeze",                  freeze_trait;
 
     DropTraitLangItem,               "drop",                    drop_trait;
 
index c690795b3421dfb82d3e6eaddeccdf5627d49730..a1cb848213a8f5043f973f5f07f6e8ff57e94b30 100644 (file)
@@ -24,8 +24,7 @@
     /// 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 @@ pub fn when(&self, cond: bool) -> 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 @@ fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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 => {
index 78d3885bb988aefca22d1fe06b6762d47e4df7e3..7325235ca7b7648c746a8d181c2f08932e99d1d9 100644 (file)
@@ -425,6 +425,8 @@ pub enum FragmentInfo {
         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 @@ pub fn with_caller_bounds(&self,
             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 @@ pub fn empty_parameter_environment(self) -> ParameterEnvironment<'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 @@ pub fn construct_parameter_environment(self,
             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));
index 5334ee2835db2325f6bcbf4066069efb6ad7c1a9..d43d570397b442d1e06de14b55e141414bdc022b 100644 (file)
@@ -655,6 +655,50 @@ fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, '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>> {
index 1313b24fa74f5eecc5311586c9f12e10f406b51c..cc7d25628432efea45b8822da752ebea2374478e 100644 (file)
@@ -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) {
index 2c4439f80a23906e250356a4a0d86729d90adfe6..535c6a7ab9e126f1e050c4845ecbd0f029544036 100644 (file)
@@ -46,7 +46,7 @@
 
 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 @@ fn check_const_eval(&self, expr: &'gcx hir::Expr) {
 
     // 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;
         }
 
index c4fdc46d030c9e163d2b0a9d8d2f4637f8f5ef58..e0a75f3caa7b36976e003b274603bc5749bdf513 100644 (file)
@@ -746,13 +746,13 @@ pub fn unadjusted(ccx: &CrateContext<'a, '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);
                 }
 
index 7a53a03344fcba2046f7a20e15f5679ffe72e4fa..eb3ac309be16d252353b10468c59927b3dd4d133 100644 (file)
@@ -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);
             }
         }
index c3770470bfd056536d620c38affa728d11e11aa7..fd9ff17cc64891f5623801278b65cfd91bb98c24 100644 (file)
@@ -399,6 +399,10 @@ pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
         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
     }