]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #41445 - frewsxcv:rollup, r=frewsxcv
authorbors <bors@rust-lang.org>
Fri, 21 Apr 2017 16:36:41 +0000 (16:36 +0000)
committerbors <bors@rust-lang.org>
Fri, 21 Apr 2017 16:36:41 +0000 (16:36 +0000)
Rollup of 4 pull requests

- Successful merges: #41372, #41376, #41426, #41429
- Failed merges:

20 files changed:
src/bootstrap/compile.rs
src/libcore/marker.rs
src/librustc/middle/lang_items.rs
src/librustc/ty/contents.rs [deleted file]
src/librustc/ty/context.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/librustc_borrowck/borrowck/mir/mod.rs
src/librustc_lint/builtin.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_passes/consts.rs
src/librustc_trans/abi.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/rtstartup/rsbegin.rs
src/test/run-make/simd-ffi/simd.rs
src/test/run-make/target-specs/foo.rs

index bddd570a13d2640bfc26b8d63fb769e9f76fad95..cd87b27d4f1aa65650ce896b85ecf0411d4f0c08 100644 (file)
@@ -151,6 +151,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
         if !up_to_date(src_file, dst_file) {
             let mut cmd = Command::new(&compiler_path);
             build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
+                        .arg("--cfg").arg(format!("stage{}", compiler.stage))
                         .arg("--target").arg(target)
                         .arg("--emit=obj")
                         .arg("--out-dir").arg(dst_dir)
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;
 
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
deleted file mode 100644 (file)
index e142959..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use hir::def_id::{DefId};
-use ty::{self, Ty, TyCtxt};
-use util::common::MemoizationMap;
-use util::nodemap::FxHashMap;
-
-use std::fmt;
-use std::ops;
-
-use syntax::ast;
-
-/// Type contents is how the type checker reasons about kinds.
-/// They track what kinds of things are found within a type.  You can
-/// think of them as kind of an "anti-kind".  They track the kinds of values
-/// and thinks that are contained in types.  Having a larger contents for
-/// a type tends to rule that type *out* from various kinds.  For example,
-/// a type that contains a reference is not sendable.
-///
-/// The reason we compute type contents and not kinds is that it is
-/// easier for me (nmatsakis) to think about what is contained within
-/// a type than to think about what is *not* contained within a type.
-#[derive(Clone, Copy)]
-pub struct TypeContents {
-    pub bits: u64
-}
-
-macro_rules! def_type_content_sets {
-    (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
-        #[allow(non_snake_case)]
-        mod $mname {
-            use super::TypeContents;
-            $(
-                #[allow(non_upper_case_globals)]
-                pub const $name: TypeContents = TypeContents { bits: $bits };
-             )+
-        }
-    }
-}
-
-def_type_content_sets! {
-    mod TC {
-        None                                = 0b0000_0000__0000_0000__0000,
-
-        // Things that are interior to the value (first nibble):
-        InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
-        InteriorParam                       = 0b0000_0000__0000_0000__0100,
-        // InteriorAll                         = 0b00000000__00000000__1111,
-
-        // Things that are owned by the value (second and third nibbles):
-        OwnsDtor                            = 0b0000_0000__0000_0010__0000,
-        // OwnsAll                             = 0b0000_0000__1111_1111__0000,
-
-        // All bits
-        All                                 = 0b1111_1111__1111_1111__1111
-    }
-}
-
-impl TypeContents {
-    pub fn when(&self, cond: bool) -> TypeContents {
-        if cond {*self} else {TC::None}
-    }
-
-    pub fn intersects(&self, tc: TypeContents) -> bool {
-        (self.bits & tc.bits) != 0
-    }
-
-    pub fn interior_param(&self) -> bool {
-        self.intersects(TC::InteriorParam)
-    }
-
-    pub fn interior_unsafe(&self) -> bool {
-        self.intersects(TC::InteriorUnsafe)
-    }
-
-    pub fn needs_drop(&self, _: TyCtxt) -> bool {
-        self.intersects(TC::OwnsDtor)
-    }
-
-    pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
-        I: IntoIterator<Item=T>,
-        F: FnMut(T) -> TypeContents,
-    {
-        v.into_iter().fold(TC::None, |tc, ty| tc | f(ty))
-    }
-}
-
-impl ops::BitOr for TypeContents {
-    type Output = TypeContents;
-
-    fn bitor(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits | other.bits}
-    }
-}
-
-impl ops::BitAnd for TypeContents {
-    type Output = TypeContents;
-
-    fn bitand(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & other.bits}
-    }
-}
-
-impl ops::Sub for TypeContents {
-    type Output = TypeContents;
-
-    fn sub(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & !other.bits}
-    }
-}
-
-impl fmt::Debug for TypeContents {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeContents({:b})", self.bits)
-    }
-}
-
-impl<'a, 'tcx> ty::TyS<'tcx> {
-    pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents {
-        return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap()));
-
-        fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           ty: Ty<'tcx>,
-                           cache: &mut FxHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
-        {
-            // Subtle: Note that we are *not* using tcx.tc_cache here but rather a
-            // private cache for this walk.  This is needed in the case of cyclic
-            // types like:
-            //
-            //     struct List { next: Box<Option<List>>, ... }
-            //
-            // When computing the type contents of such a type, we wind up deeply
-            // recursing as we go.  So when we encounter the recursive reference
-            // to List, we temporarily use TC::None as its contents.  Later we'll
-            // patch up the cache with the correct value, once we've computed it
-            // (this is basically a co-inductive process, if that helps).  So in
-            // the end we'll compute TC::OwnsOwned, in this case.
-            //
-            // The problem is, as we are doing the computation, we will also
-            // compute an *intermediate* contents for, e.g., Option<List> of
-            // TC::None.  This is ok during the computation of List itself, but if
-            // we stored this intermediate value into tcx.tc_cache, then later
-            // requests for the contents of Option<List> would also yield TC::None
-            // which is incorrect.  This value was computed based on the crutch
-            // value for the type contents of list.  The correct value is
-            // TC::OwnsOwned.  This manifested as issue #4821.
-            if let Some(tc) = cache.get(&ty) {
-                return *tc;
-            }
-            // Must check both caches!
-            if let Some(tc) = tcx.tc_cache.borrow().get(&ty) {
-                return *tc;
-            }
-            cache.insert(ty, TC::None);
-
-            let result = match ty.sty {
-                // usize and isize are ffi-unsafe
-                ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => {
-                    TC::None
-                }
-
-                // Scalar and unique types are sendable, and durable
-                ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
-                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
-                ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
-                    TC::None
-                }
-
-                ty::TyDynamic(..) => {
-                    TC::All - TC::InteriorParam
-                }
-
-                ty::TyRawPtr(_) => {
-                    TC::None
-                }
-
-                ty::TyRef(..) => {
-                    TC::None
-                }
-
-                ty::TyArray(ty, _) => {
-                    tc_ty(tcx, ty, cache)
-                }
-
-                ty::TySlice(ty) => {
-                    tc_ty(tcx, ty, cache)
-                }
-                ty::TyStr => TC::None,
-
-                ty::TyClosure(def_id, ref substs) => {
-                    TypeContents::union(
-                        substs.upvar_tys(def_id, tcx),
-                        |ty| tc_ty(tcx, &ty, cache))
-                }
-
-                ty::TyTuple(ref tys, _) => {
-                    TypeContents::union(&tys[..],
-                                        |ty| tc_ty(tcx, *ty, cache))
-                }
-
-                ty::TyAdt(def, substs) => {
-                    let mut res =
-                        TypeContents::union(&def.variants, |v| {
-                            TypeContents::union(&v.fields, |f| {
-                                tc_ty(tcx, f.ty(tcx, substs), cache)
-                            })
-                        });
-
-                    if def.is_union() {
-                        // unions don't have destructors regardless of the child types
-                        res = res - TC::OwnsDtor;
-                    }
-
-                    if def.has_dtor(tcx) {
-                        res = res | TC::OwnsDtor;
-                    }
-
-                    apply_lang_items(tcx, def.did, res)
-                }
-
-                ty::TyProjection(..) |
-                ty::TyParam(_) |
-                ty::TyAnon(..) => {
-                    TC::All
-                }
-
-                ty::TyInfer(_) |
-                ty::TyError => {
-                    bug!("asked to compute contents of error type");
-                }
-            };
-
-            cache.insert(ty, result);
-            result
-        }
-
-        fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                      did: DefId, tc: TypeContents)
-                                      -> TypeContents {
-            if Some(did) == tcx.lang_items.unsafe_cell_type() {
-                tc | TC::InteriorUnsafe
-            } else {
-                tc
-            }
-        }
-    }
-}
index 8b7438c0bfad2ed5f73efbfece42ffbbd22978d4..a41629258716d51dc991639bc4654c129daaa48e 100644 (file)
@@ -436,9 +436,6 @@ pub struct GlobalCtxt<'tcx> {
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
 
-    // Cache for the type-contents routine. FIXME -- track deps?
-    pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
-
     // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
@@ -708,7 +705,6 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             freevars: RefCell::new(resolutions.freevars),
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
             rcache: RefCell::new(FxHashMap()),
-            tc_cache: RefCell::new(FxHashMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
index ab1a06aeacd182990a362773cf9db929a911cccb..5c0889976c21a7bd8f462030899ac58b51429368 100644 (file)
@@ -71,7 +71,6 @@
 pub use self::sty::Region::*;
 pub use self::sty::TypeVariants::*;
 
-pub use self::contents::TypeContents;
 pub use self::context::{TyCtxt, GlobalArenas, tls};
 pub use self::context::{Lift, TypeckTables};
 
@@ -99,7 +98,6 @@
 pub mod wf;
 pub mod util;
 
-mod contents;
 mod context;
 mod flags;
 mod instance;
@@ -425,6 +423,10 @@ 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,
+        const NEEDS_DROP_CACHED = 1 << 22,
+        const NEEDS_DROP        = 1 << 23,
     }
 }
 
@@ -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()),
         }
     }
 
@@ -2375,40 +2381,6 @@ pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
         Some(self.item_mir(did))
     }
 
-    /// If `type_needs_drop` returns true, then `ty` is definitely
-    /// non-copy and *might* have a destructor attached; if it returns
-    /// false, then `ty` definitely has no destructor (i.e. no drop glue).
-    ///
-    /// (Note that this implies that if `ty` has a destructor attached,
-    /// then `type_needs_drop` will definitely return `true` for `ty`.)
-    pub fn type_needs_drop_given_env(self,
-                                     ty: Ty<'gcx>,
-                                     param_env: &ty::ParameterEnvironment<'gcx>) -> bool {
-        // Issue #22536: We first query type_moves_by_default.  It sees a
-        // normalized version of the type, and therefore will definitely
-        // know whether the type implements Copy (and thus needs no
-        // cleanup/drop/zeroing) ...
-        let tcx = self.global_tcx();
-        let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP);
-
-        if implements_copy { return false; }
-
-        // ... (issue #22536 continued) but as an optimization, still use
-        // prior logic of asking if the `needs_drop` bit is set; we need
-        // not zero non-Copy types if they have no destructor.
-
-        // FIXME(#22815): Note that calling `ty::type_contents` is a
-        // conservative heuristic; it may report that `needs_drop` is set
-        // when actual type does not actually have a destructor associated
-        // with it. But since `ty` absolutely did not have the `Copy`
-        // bound attached (see above), it is sound to treat it as having a
-        // destructor (e.g. zero its memory on move).
-
-        let contents = ty.type_contents(tcx);
-        debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
-        contents.needs_drop(tcx)
-    }
-
     /// Get the attributes of a definition.
     pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> {
         if let Some(id) = self.hir.as_local_node_id(did) {
@@ -2531,6 +2503,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 +2576,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..49d79f6545e2dd682b3cb1ff55ac936f7fced871 100644 (file)
@@ -21,7 +21,7 @@
 use ty::layout::{Layout, LayoutError};
 use ty::TypeVariants::*;
 use util::common::ErrorReported;
-use util::nodemap::FxHashMap;
+use util::nodemap::{FxHashMap, FxHashSet};
 use middle::lang_items;
 
 use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
@@ -655,6 +655,165 @@ 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
+    }
+
+    /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
+    /// non-copy and *might* have a destructor attached; if it returns
+    /// `false`, then `ty` definitely has no destructor (i.e. no drop glue).
+    ///
+    /// (Note that this implies that if `ty` has a destructor attached,
+    /// then `needs_drop` will definitely return `true` for `ty`.)
+    #[inline]
+    pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    param_env: &ty::ParameterEnvironment<'tcx>) -> bool {
+        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
+            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
+        }
+
+        self.needs_drop_uncached(tcx, param_env, &mut FxHashSet())
+    }
+
+    fn needs_drop_inner(&'tcx self,
+                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        param_env: &ty::ParameterEnvironment<'tcx>,
+                        stack: &mut FxHashSet<Ty<'tcx>>)
+                        -> bool {
+        if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
+            return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
+        }
+
+        // This should be reported as an error by `check_representable`.
+        //
+        // Consider the type as not needing drop in the meanwhile to avoid
+        // further errors.
+        if let Some(_) = stack.replace(self) {
+            return false;
+        }
+
+        let needs_drop = self.needs_drop_uncached(tcx, param_env, stack);
+
+        // "Pop" the cycle detection "stack".
+        stack.remove(self);
+
+        needs_drop
+    }
+
+    fn needs_drop_uncached(&'tcx self,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           param_env: &ty::ParameterEnvironment<'tcx>,
+                           stack: &mut FxHashSet<Ty<'tcx>>)
+                           -> bool {
+        assert!(!self.needs_infer());
+
+        let result = match self.sty {
+            // Fast-path for primitive types
+            ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+            ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+            ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
+
+            // Issue #22536: We first query type_moves_by_default.  It sees a
+            // normalized version of the type, and therefore will definitely
+            // know whether the type implements Copy (and thus needs no
+            // cleanup/drop/zeroing) ...
+            _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false,
+
+            // ... (issue #22536 continued) but as an optimization, still use
+            // prior logic of asking for the structural "may drop".
+
+            // FIXME(#22815): Note that this is a conservative heuristic;
+            // it may report that the type "may drop" when actual type does
+            // not actually have a destructor associated with it. But since
+            // the type absolutely did not have the `Copy` bound attached
+            // (see above), it is sound to treat it as having a destructor.
+
+            // User destructors are the only way to have concrete drop types.
+            ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
+
+            // Can refer to a type which may drop.
+            // FIXME(eddyb) check this against a ParameterEnvironment.
+            ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
+            ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
+
+            // Structural recursion.
+            ty::TyArray(ty, _) | ty::TySlice(ty) => {
+                ty.needs_drop_inner(tcx, param_env, stack)
+            }
+
+            ty::TyClosure(def_id, ref substs) => {
+                substs.upvar_tys(def_id, tcx)
+                    .any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
+            }
+
+            ty::TyTuple(ref tys, _) => {
+                tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
+            }
+
+            // unions don't have destructors regardless of the child types
+            ty::TyAdt(def, _) if def.is_union() => false,
+
+            ty::TyAdt(def, substs) => {
+                def.variants.iter().any(|v| {
+                    v.fields.iter().any(|f| {
+                        f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack)
+                    })
+                })
+            }
+        };
+
+        if !self.has_param_types() && !self.has_self_ty() {
+            self.flags.set(self.flags.get() | if result {
+                TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP
+            } else {
+                TypeFlags::NEEDS_DROP_CACHED
+            });
+        }
+
+        result
+    }
+
     #[inline]
     pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
                         -> Result<&'tcx Layout, LayoutError<'tcx>> {
index dc01cbe5e7605eb3a4fd4a9e19e269d25fe531a8..de5613dbfaa38b183c8d34d4584c233191501805 100644 (file)
@@ -322,7 +322,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>(
         let ty = lvalue.ty(mir, tcx).to_ty(tcx);
         debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty);
 
-        if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) {
+        if ty.needs_drop(tcx, &ctxt.param_env) {
             each_child(child);
         } else {
             debug!("on_all_drop_children_bits - skipping")
index 0ee9d4a42c7f81a26c15efdb0a37ab3eb5af6b45..1c69f3cff172a4321a49062bfcffcf3397e6c0fa 100644 (file)
@@ -1152,7 +1152,7 @@ fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
             let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
             for field in vdata.fields() {
                 let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id));
-                if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
+                if field_ty.needs_drop(ctx.tcx, param_env) {
                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
                                   field.span,
                                   "union contains a field with possibly non-trivial drop code, \
index 5f9fb8e1b120f040c57486f2cf285e0ed1b512e7..db9da2a280b94cc70af7e43645fef9e0e1b247bf 100644 (file)
@@ -168,7 +168,7 @@ pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
                   type with inference types/regions",
                  ty);
         });
-        self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment)
+        ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment)
     }
 
     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
index ac2bdaad24f766a397d2f5c53da0b3bc0bf877f1..892d67ac23725f2bd7015be805006a96bee95190 100644 (file)
@@ -357,7 +357,7 @@ fn should_inline(&self, callsite: CallSite<'tcx>,
                     // a regular goto.
                     let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
                     let ty = ty.to_ty(tcx);
-                    if tcx.type_needs_drop_given_env(ty, &param_env) {
+                    if ty.needs_drop(tcx, &param_env) {
                         cost += CALL_PENALTY;
                         if let Some(unwind) = unwind {
                             work_list.push(unwind);
index 1313b24fa74f5eecc5311586c9f12e10f406b51c..526c1488ab480e96fe6873c985548f3cb7d8b610 100644 (file)
@@ -80,10 +80,10 @@ 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) {
+        if !ty.needs_drop(tcx, param_env) {
             *self = *self - Qualif::NEEDS_DROP;
         }
     }
index 04a1fc891cf1e582e2ef50d2b4271bf8df16bd6c..07025fcfdb944de518e3e1dff13abb71f1611a48 100644 (file)
@@ -277,8 +277,7 @@ fn drop_ladder<'a>(&mut self,
 
         let mut fields = fields;
         fields.retain(|&(ref lvalue, _)| {
-            self.tcx().type_needs_drop_given_env(
-                self.lvalue_ty(lvalue), self.elaborator.param_env())
+            self.lvalue_ty(lvalue).needs_drop(self.tcx(), self.elaborator.param_env())
         });
 
         debug!("drop_ladder - fields needing drop: {:?}", fields);
index 2c4439f80a23906e250356a4a0d86729d90adfe6..fdb67522133781f74b3c2430ab58bc3aec917006 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,11 +85,11 @@ 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;
         }
 
-        if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
+        if ty.needs_drop(self.tcx, &self.param_env) {
             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..1d1921bf7b96dd1ee62f1e146ad08cb0507d39a0 100644 (file)
@@ -392,13 +392,17 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
     }
 
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env)
+        ty.needs_drop(self.tcx, &self.empty_param_env)
     }
 
     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
     }
index 65c85697ce720f6842a2fd52d6bb70626ac98d71..e8b92aab1da1e556f2518b9f7aac050ace6cd928 100644 (file)
@@ -22,7 +22,7 @@
 // object (usually called `crtX.o), which then invokes initialization callbacks
 // of other runtime components (registered via yet another special image section).
 
-#![feature(no_core, lang_items)]
+#![feature(no_core, lang_items, optin_builtin_traits)]
 #![crate_type="rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
 trait Sized {}
 #[lang = "sync"]
 trait Sync {}
+impl Sync for .. {}
 #[lang = "copy"]
 trait Copy {}
-impl<T> Sync for T {}
+#[cfg_attr(not(stage0), lang = "freeze")]
+trait Freeze {}
+impl Freeze for .. {}
 
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
 pub mod eh_frames {
index 49fec6f3619e4fa9c7ed48562281a8cfaf8d50e9..8ab8f4715755ddbef149777ab726c29d023afe0f 100644 (file)
@@ -12,7 +12,7 @@
 #![crate_type = "lib"]
 // we can compile to a variety of platforms, because we don't need
 // cross-compiled standard libraries.
-#![feature(no_core)]
+#![feature(no_core, optin_builtin_traits)]
 #![no_core]
 
 #![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)]
@@ -78,3 +78,7 @@ pub trait Copy { }
 pub mod marker {
     pub use Copy;
 }
+
+#[lang = "freeze"]
+trait Freeze {}
+impl Freeze for .. {}
index 15b56977232169cf5b8721ba0994cd9947712839..af24c3b460b2e844d43123eb9aaf9f6725967996 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(lang_items, no_core)]
+#![feature(lang_items, no_core, optin_builtin_traits)]
 #![no_core]
 
 #[lang="copy"]
@@ -17,6 +17,10 @@ trait Copy { }
 #[lang="sized"]
 trait Sized { }
 
+#[lang = "freeze"]
+trait Freeze {}
+impl Freeze for .. {}
+
 #[lang="start"]
 fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 }