about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-09-14 09:47:21 +0000
committerbors <bors@rust-lang.org>2018-09-14 09:47:21 +0000
commitdfabe4b88509bfff1eca9060ccc9a4d28ee394e8 (patch)
tree7f637c2857e19dfbcc17254c011e644de2306e65
parentfccde0018a618eb6f45d2a3c97f629809994dff6 (diff)
parenta94c16614c3a43d609a437afa92ef5ae7d3965ea (diff)
downloadrust-dfabe4b88509bfff1eca9060ccc9a4d28ee394e8.tar.gz
rust-dfabe4b88509bfff1eca9060ccc9a4d28ee394e8.zip
Auto merge of #54032 - oli-obk:layout_scalar_ranges, r=eddyb
Add forever unstable attribute to allow specifying arbitrary scalar ranges

r? @eddyb for the first commit and @nikomatsakis for the second one
-rw-r--r--src/libcore/nonzero.rs3
-rw-r--r--src/librustc/hir/def_id.rs85
-rw-r--r--src/librustc/ich/impls_ty.rs15
-rw-r--r--src/librustc/infer/error_reporting/mod.rs12
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/region.rs128
-rw-r--r--src/librustc/ty/context.rs32
-rw-r--r--src/librustc/ty/layout.rs39
-rw-r--r--src/librustc/ty/query/on_disk_cache.rs5
-rw-r--r--src/librustc/util/ppaux.rs27
-rw-r--r--src/librustc_data_structures/indexed_vec.rs7
-rw-r--r--src/librustc_mir/build/cfg.rs2
-rw-r--r--src/librustc_mir/build/scope.rs2
-rw-r--r--src/librustc_mir/hair/cx/block.rs10
-rw-r--r--src/librustc_mir/interpret/operand.rs14
-rw-r--r--src/librustc_mir/lib.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs4
-rw-r--r--src/librustc_resolve/macros.rs10
-rw-r--r--src/test/mir-opt/validate_1.rs6
-rw-r--r--src/test/mir-opt/validate_3.rs8
-rw-r--r--src/test/run-pass-fulldeps/newtype_index.rs20
-rw-r--r--src/test/ui/consts/const-eval/zst_operand_eval.rs5
23 files changed, 279 insertions, 161 deletions
diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs
index cc36ea7f713..30067d7e163 100644
--- a/src/libcore/nonzero.rs
+++ b/src/libcore/nonzero.rs
@@ -14,7 +14,8 @@ use ops::CoerceUnsized;
 
 /// A wrapper type for raw pointers and integers that will never be
 /// NULL or 0 that might allow certain optimizations.
-#[lang = "non_zero"]
+#[cfg_attr(stage0, lang = "non_zero")]
+#[cfg_attr(not(stage0), rustc_layout_scalar_valid_range_start(1))]
 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[repr(transparent)]
 pub(crate) struct NonZero<T>(pub(crate) T);
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 420ffbcfee6..cd91b85689b 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -16,25 +16,53 @@ use std::fmt;
 use std::u32;
 
 newtype_index! {
-    pub struct CrateNum {
+    pub struct CrateId {
         ENCODABLE = custom
-        DEBUG_FORMAT = "crate{}",
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum CrateNum {
+    /// Virtual crate for builtin macros
+    // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
+    // `CrateNum`s.
+    BuiltinMacros,
+    /// A CrateNum value that indicates that something is wrong.
+    Invalid,
+    /// A special CrateNum that we use for the tcx.rcache when decoding from
+    /// the incr. comp. cache.
+    ReservedForIncrCompCache,
+    Index(CrateId),
+}
+
+impl ::std::fmt::Debug for CrateNum {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        match self {
+            CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
+            CrateNum::Invalid => write!(fmt, "invalid crate"),
+            CrateNum::BuiltinMacros => write!(fmt, "bultin macros crate"),
+            CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
+        }
+    }
+}
 
-        /// Item definitions in the currently-compiled crate would have the CrateNum
-        /// LOCAL_CRATE in their DefId.
-        const LOCAL_CRATE = 0,
+/// Item definitions in the currently-compiled crate would have the CrateNum
+/// LOCAL_CRATE in their DefId.
+pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32_const(0));
 
-        /// Virtual crate for builtin macros
-        // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
-        // `CrateNum`s.
-        const BUILTIN_MACROS_CRATE = CrateNum::MAX_AS_U32,
 
-        /// A CrateNum value that indicates that something is wrong.
-        const INVALID_CRATE = CrateNum::MAX_AS_U32 - 1,
+impl Idx for CrateNum {
+    #[inline]
+    fn new(value: usize) -> Self {
+        CrateNum::Index(Idx::new(value))
+    }
 
-        /// A special CrateNum that we use for the tcx.rcache when decoding from
-        /// the incr. comp. cache.
-        const RESERVED_FOR_INCR_COMP_CACHE = CrateNum::MAX_AS_U32 - 2,
+    #[inline]
+    fn index(self) -> usize {
+        match self {
+            CrateNum::Index(idx) => Idx::index(idx),
+            _ => bug!("Tried to get crate index of {:?}", self),
+        }
     }
 }
 
@@ -43,12 +71,39 @@ impl CrateNum {
         CrateNum::from_usize(x)
     }
 
+    pub fn from_usize(x: usize) -> CrateNum {
+        CrateNum::Index(CrateId::from_usize(x))
+    }
+
+    pub fn from_u32(x: u32) -> CrateNum {
+        CrateNum::Index(CrateId::from_u32(x))
+    }
+
+    pub fn as_usize(self) -> usize {
+        match self {
+            CrateNum::Index(id) => id.as_usize(),
+            _ => bug!("tried to get index of nonstandard crate {:?}", self),
+        }
+    }
+
+    pub fn as_u32(self) -> u32 {
+        match self {
+            CrateNum::Index(id) => id.as_u32(),
+            _ => bug!("tried to get index of nonstandard crate {:?}", self),
+        }
+    }
+
     pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
 }
 
 impl fmt::Display for CrateNum {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.as_u32(), f)
+        match self {
+            CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
+            CrateNum::Invalid => write!(f, "invalid crate"),
+            CrateNum::BuiltinMacros => write!(f, "bultin macros crate"),
+            CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
+        }
     }
 }
 
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 16175e159dd..2bf1c79c8a4 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -772,7 +772,15 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
     FnPtrAddrCast
 });
 
-impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
+impl_stable_hash_for!(struct ::middle::region::Scope { id, data });
+
+impl_stable_hash_for!(enum ::middle::region::ScopeData {
+    Node,
+    CallSite,
+    Arguments,
+    Destruction,
+    Remainder(first_statement_index)
+});
 
 impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
     type KeyType = region::Scope;
@@ -783,11 +791,6 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
     }
 }
 
-impl_stable_hash_for!(struct ::middle::region::BlockRemainder {
-    block,
-    first_statement_index
-});
-
 impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
     custom_kind
 });
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index eabcf1ce413..a0c96554c91 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -119,17 +119,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     }
                 };
                 let scope_decorated_tag = match scope.data() {
-                    region::ScopeData::Node(_) => tag,
-                    region::ScopeData::CallSite(_) => "scope of call-site for function",
-                    region::ScopeData::Arguments(_) => "scope of function body",
-                    region::ScopeData::Destruction(_) => {
+                    region::ScopeData::Node => tag,
+                    region::ScopeData::CallSite => "scope of call-site for function",
+                    region::ScopeData::Arguments => "scope of function body",
+                    region::ScopeData::Destruction => {
                         new_string = format!("destruction scope surrounding {}", tag);
                         &new_string[..]
                     }
-                    region::ScopeData::Remainder(r) => {
+                    region::ScopeData::Remainder(first_statement_index) => {
                         new_string = format!(
                             "block suffix following statement {}",
-                            r.first_statement_index.index()
+                            first_statement_index.index()
                         );
                         &new_string[..]
                     }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 56096a5d423..c017c90b895 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -58,6 +58,8 @@
 #![feature(optin_builtin_traits)]
 #![feature(refcell_replace_swap)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(rustc_attrs)]
+#![cfg_attr(stage0, feature(attr_literals))]
 #![feature(slice_patterns)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(specialization)]
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index d92f856fa4d..bfde4e4a3ae 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -326,8 +326,6 @@ language_item_table! {
 
     PhantomDataItem,                 "phantom_data",            phantom_data;
 
-    NonZeroItem,                     "non_zero",                non_zero;
-
     ManuallyDropItem,                "manually_drop",           manually_drop;
 
     DebugTraitLangItem,              "debug_trait",             debug_trait;
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index f6a8f8dc172..2f99743cfbd 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -20,8 +20,8 @@ use ich::{StableHashingContext, NodeIdHashingMode};
 use util::nodemap::{FxHashMap, FxHashSet};
 use ty;
 
-use std::fmt;
 use std::mem;
+use std::fmt;
 use rustc_data_structures::sync::Lrc;
 use syntax::source_map;
 use syntax::ast;
@@ -51,7 +51,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
 /// `DestructionScope`, but those that are `terminating_scopes` do;
 /// see discussion with `ScopeTree`.
 ///
-/// `Remainder(BlockRemainder { block, statement_index })` represents
+/// `Remainder { block, statement_index }` represents
 /// the scope of user code running immediately after the initializer
 /// expression for the indexed statement, until the end of the block.
 ///
@@ -100,39 +100,46 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
 /// placate the same deriving in `ty::FreeRegion`, but we may want to
 /// actually attach a more meaningful ordering to scopes than the one
 /// generated via deriving here.
-///
-/// Scope is a bit-packed to save space - if `code` is SCOPE_DATA_REMAINDER_MAX
-/// or less, it is a `ScopeData::Remainder`, otherwise it is a type specified
-/// by the bitpacking.
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, RustcEncodable, RustcDecodable)]
 pub struct Scope {
     pub(crate) id: hir::ItemLocalId,
-    pub(crate) code: u32
+    pub(crate) data: ScopeData,
 }
 
-const SCOPE_DATA_NODE: u32 = !0;
-const SCOPE_DATA_CALLSITE: u32 = !1;
-const SCOPE_DATA_ARGUMENTS: u32 = !2;
-const SCOPE_DATA_DESTRUCTION: u32 = !3;
-const SCOPE_DATA_REMAINDER_MAX: u32 = !4;
+impl fmt::Debug for Scope {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match self.data {
+            ScopeData::Node => write!(fmt, "Node({:?})", self.id),
+            ScopeData::CallSite => write!(fmt, "CallSite({:?})", self.id),
+            ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id),
+            ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id),
+            ScopeData::Remainder(fsi) => write!(
+                fmt,
+                "Remainder {{ block: {:?}, first_statement_index: {}}}",
+                self.id,
+                fsi.as_u32(),
+            ),
+        }
+    }
+}
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
 pub enum ScopeData {
-    Node(hir::ItemLocalId),
+    Node,
 
     // Scope of the call-site for a function or closure
     // (outlives the arguments as well as the body).
-    CallSite(hir::ItemLocalId),
+    CallSite,
 
     // Scope of arguments passed to a function or closure
     // (they outlive its body).
-    Arguments(hir::ItemLocalId),
+    Arguments,
 
     // Scope of destructors for temporaries of node-id.
-    Destruction(hir::ItemLocalId),
+    Destruction,
 
     // Scope following a `let id = expr;` binding in a block.
-    Remainder(BlockRemainder)
+    Remainder(FirstStatementIndex)
 }
 
 /// Represents a subscope of `block` for a binding that is introduced
@@ -152,83 +159,61 @@ pub enum ScopeData {
 ///
 /// * the subscope with `first_statement_index == 1` is scope of `c`,
 ///   and thus does not include EXPR_2, but covers the `...`.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
-         RustcDecodable, Debug, Copy)]
-pub struct BlockRemainder {
-    pub block: hir::ItemLocalId,
-    pub first_statement_index: FirstStatementIndex,
-}
 
 newtype_index! {
-    pub struct FirstStatementIndex {
-        MAX = SCOPE_DATA_REMAINDER_MAX
-    }
+    pub struct FirstStatementIndex { .. }
 }
 
 impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { private });
 
-impl From<ScopeData> for Scope {
-    #[inline]
-    fn from(scope_data: ScopeData) -> Self {
-        let (id, code) = match scope_data {
-            ScopeData::Node(id) => (id, SCOPE_DATA_NODE),
-            ScopeData::CallSite(id) => (id, SCOPE_DATA_CALLSITE),
-            ScopeData::Arguments(id) => (id, SCOPE_DATA_ARGUMENTS),
-            ScopeData::Destruction(id) => (id, SCOPE_DATA_DESTRUCTION),
-            ScopeData::Remainder(r) => (r.block, r.first_statement_index.index() as u32)
-        };
-        Self { id, code }
-    }
-}
-
-impl fmt::Debug for Scope {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.data(), formatter)
-    }
-}
+// compilation error if size of `ScopeData` is not the same as a `u32`
+#[allow(dead_code)]
+// only works on stage 1 when the rustc_layout_scalar_valid_range attribute actually exists
+#[cfg(not(stage0))]
+static ASSERT: () = [()][!(mem::size_of::<ScopeData>() == 4) as usize];
 
 #[allow(non_snake_case)]
 impl Scope {
     #[inline]
     pub fn data(self) -> ScopeData {
-        match self.code {
-            SCOPE_DATA_NODE => ScopeData::Node(self.id),
-            SCOPE_DATA_CALLSITE => ScopeData::CallSite(self.id),
-            SCOPE_DATA_ARGUMENTS => ScopeData::Arguments(self.id),
-            SCOPE_DATA_DESTRUCTION => ScopeData::Destruction(self.id),
-            idx => ScopeData::Remainder(BlockRemainder {
-                block: self.id,
-                first_statement_index: FirstStatementIndex::new(idx as usize)
-            })
-        }
+        self.data
+    }
+
+    #[inline]
+    pub fn new(id: hir::ItemLocalId, data: ScopeData) -> Self {
+        Scope { id, data }
     }
 
     #[inline]
     pub fn Node(id: hir::ItemLocalId) -> Self {
-        Self::from(ScopeData::Node(id))
+        Self::new(id, ScopeData::Node)
     }
 
     #[inline]
     pub fn CallSite(id: hir::ItemLocalId) -> Self {
-        Self::from(ScopeData::CallSite(id))
+        Self::new(id, ScopeData::CallSite)
     }
 
     #[inline]
     pub fn Arguments(id: hir::ItemLocalId) -> Self {
-        Self::from(ScopeData::Arguments(id))
+        Self::new(id, ScopeData::Arguments)
     }
 
     #[inline]
     pub fn Destruction(id: hir::ItemLocalId) -> Self {
-        Self::from(ScopeData::Destruction(id))
+        Self::new(id, ScopeData::Destruction)
     }
 
     #[inline]
-    pub fn Remainder(r: BlockRemainder) -> Self {
-        Self::from(ScopeData::Remainder(r))
+    pub fn Remainder(
+        id: hir::ItemLocalId,
+        first: FirstStatementIndex,
+    ) -> Self {
+        Self::new(id, ScopeData::Remainder(first))
     }
 }
 
+
 impl Scope {
     /// Returns a item-local id associated with this scope.
     ///
@@ -259,7 +244,7 @@ impl Scope {
             return DUMMY_SP;
         }
         let span = tcx.hir.span(node_id);
-        if let ScopeData::Remainder(r) = self.data() {
+        if let ScopeData::Remainder(first_statement_index) = self.data() {
             if let Node::Block(ref blk) = tcx.hir.get(node_id) {
                 // Want span for scope starting after the
                 // indexed statement and ending at end of
@@ -269,7 +254,7 @@ impl Scope {
                 // (This is the special case aluded to in the
                 // doc-comment for this method)
 
-                let stmt_span = blk.stmts[r.first_statement_index.index()].span;
+                let stmt_span = blk.stmts[first_statement_index.index()].span;
 
                 // To avoid issues with macro-generated spans, the span
                 // of the statement must be nested in that of the block.
@@ -513,8 +498,8 @@ impl<'tcx> ScopeTree {
         }
 
         // record the destruction scopes for later so we can query them
-        if let ScopeData::Destruction(n) = child.data() {
-            self.destruction_scopes.insert(n, child);
+        if let ScopeData::Destruction = child.data() {
+            self.destruction_scopes.insert(child.item_local_id(), child);
         }
     }
 
@@ -597,7 +582,7 @@ impl<'tcx> ScopeTree {
 
         while let Some(&(p, _)) = self.parent_map.get(&id) {
             match p.data() {
-                ScopeData::Destruction(..) => {
+                ScopeData::Destruction => {
                     debug!("temporary_scope({:?}) = {:?} [enclosing]",
                            expr_id, id);
                     return Some(id);
@@ -652,8 +637,8 @@ impl<'tcx> ScopeTree {
     /// Returns the id of the innermost containing body
     pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
         loop {
-            if let ScopeData::CallSite(id) = scope.data() {
-                return Some(id);
+            if let ScopeData::CallSite = scope.data() {
+                return Some(scope.item_local_id());
             }
 
             match self.opt_encl_scope(scope) {
@@ -869,10 +854,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
                 // except for the first such subscope, which has the
                 // block itself as a parent.
                 visitor.enter_scope(
-                    Scope::Remainder(BlockRemainder {
-                        block: blk.hir_id.local_id,
-                        first_statement_index: FirstStatementIndex::new(i)
-                    })
+                    Scope::Remainder(blk.hir_id.local_id, FirstStatementIndex::new(i))
                 );
                 visitor.cx.var_parent = visitor.cx.parent;
             }
@@ -1035,7 +1017,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
             match visitor.scope_tree.parent_map.get(&scope) {
                 // Don't cross from closure bodies to their parent.
                 Some(&(superscope, _)) => match superscope.data() {
-                    ScopeData::CallSite(_) => break,
+                    ScopeData::CallSite => break,
                     _ => scope = superscope
                 },
                 None => break
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6cc648b572c..d1f37250379 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -66,7 +66,7 @@ use std::collections::hash_map::{self, Entry};
 use std::hash::{Hash, Hasher};
 use std::fmt;
 use std::mem;
-use std::ops::Deref;
+use std::ops::{Deref, Bound};
 use std::iter;
 use std::sync::mpsc;
 use std::sync::Arc;
@@ -829,10 +829,12 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         // Ensure our type representation does not grow
-        #[cfg(target_pointer_width = "64")]
-        assert!(mem::size_of::<ty::TyKind>() <= 24);
-        #[cfg(target_pointer_width = "64")]
-        assert!(mem::size_of::<ty::TyS>() <= 32);
+        #[cfg(all(not(stage0), target_pointer_width = "64"))]
+        #[allow(dead_code)]
+        static ASSERT_TY_KIND: () = [()][!(::std::mem::size_of::<ty::TyKind>() <= 24) as usize];
+        #[cfg(all(not(stage0), target_pointer_width = "64"))]
+        #[allow(dead_code)]
+        static ASSERT_TYS: () = [()][!(::std::mem::size_of::<ty::TyS>() <= 32) as usize];
 
         let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
         let mk_region = |r| {
@@ -1083,6 +1085,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
+    /// Returns a range of the start/end indices specified with the
+    /// `rustc_layout_scalar_valid_range` attribute.
+    pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
+        let attrs = self.get_attrs(def_id);
+        let get = |name| {
+            let attr = match attrs.iter().find(|a| a.check_name(name)) {
+                Some(attr) => attr,
+                None => return Bound::Unbounded,
+            };
+            for meta in attr.meta_item_list().expect("rustc_layout_scalar_valid_range takes args") {
+                match meta.literal().expect("attribute takes lit").node {
+                    ast::LitKind::Int(a, _) => return Bound::Included(a),
+                    _ => span_bug!(attr.span, "rustc_layout_scalar_valid_range expects int arg"),
+                }
+            }
+            span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_range` attribute");
+        };
+        (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end"))
+    }
+
     pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
         value.lift_to_tcx(self)
     }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index a3316c2b8e2..4e37a34a0c8 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -20,6 +20,7 @@ use std::fmt;
 use std::i128;
 use std::iter;
 use std::mem;
+use std::ops::Bound;
 
 use ich::StableHashingContext;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
@@ -761,17 +762,29 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
 
                     let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
                     st.variants = Variants::Single { index: v };
-                    // Exclude 0 from the range of a newtype ABI NonZero<T>.
-                    if Some(def.did) == self.tcx.lang_items().non_zero() {
-                        match st.abi {
-                            Abi::Scalar(ref mut scalar) |
-                            Abi::ScalarPair(ref mut scalar, _) => {
-                                if *scalar.valid_range.start() == 0 {
-                                    scalar.valid_range = 1..=*scalar.valid_range.end();
-                                }
+                    let (start, end) = self.tcx.layout_scalar_valid_range(def.did);
+                    match st.abi {
+                        Abi::Scalar(ref mut scalar) |
+                        Abi::ScalarPair(ref mut scalar, _) => {
+                            // the asserts ensure that we are not using the
+                            // `#[rustc_layout_scalar_valid_range(n)]`
+                            // attribute to widen the range of anything as that would probably
+                            // result in UB somewhere
+                            if let Bound::Included(start) = start {
+                                assert!(*scalar.valid_range.start() <= start);
+                                scalar.valid_range = start..=*scalar.valid_range.end();
+                            }
+                            if let Bound::Included(end) = end {
+                                assert!(*scalar.valid_range.end() >= end);
+                                scalar.valid_range = *scalar.valid_range.start()..=end;
                             }
-                            _ => {}
                         }
+                        _ => assert!(
+                            start == Bound::Unbounded && end == Bound::Unbounded,
+                            "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}",
+                            def,
+                            st,
+                        ),
                     }
                     return Ok(tcx.intern_layout(st));
                 }
@@ -1350,8 +1363,12 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
                 if def.variants.len() == 1 {
                     if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
                         return Ok(SizeSkeleton::Pointer {
-                            non_zero: non_zero ||
-                                Some(def.did) == tcx.lang_items().non_zero(),
+                            non_zero: non_zero || match tcx.layout_scalar_valid_range(def.did) {
+                                (Bound::Included(start), Bound::Unbounded) => start > 0,
+                                (Bound::Included(start), Bound::Included(end)) =>
+                                    0 < start && start < end,
+                                _ => false,
+                            },
                             tail,
                         });
                     } else {
diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs
index 19e235154cb..0e4d2f1f647 100644
--- a/src/librustc/ty/query/on_disk_cache.rs
+++ b/src/librustc/ty/query/on_disk_cache.rs
@@ -11,8 +11,7 @@
 use dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use errors::Diagnostic;
 use hir;
-use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
-                  RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
+use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
 use hir::map::definitions::DefPathHash;
 use ich::{CachingSourceMapView, Fingerprint};
 use mir::{self, interpret};
@@ -566,7 +565,7 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
         let tcx = self.tcx();
 
         let cache_key = ty::CReaderCacheKey {
-            cnum: RESERVED_FOR_INCR_COMP_CACHE,
+            cnum: CrateNum::ReservedForIncrCompCache,
             pos: shorthand,
         };
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 3d7117dd46a..5ffb77dda68 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -11,7 +11,7 @@
 use hir::def_id::DefId;
 use hir::map::definitions::DefPathData;
 use mir::interpret::ConstValue;
-use middle::region::{self, BlockRemainder};
+use middle::region;
 use ty::subst::{self, Subst};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{Bool, Char, Adt};
@@ -770,17 +770,20 @@ define_print! {
                 }
                 ty::ReScope(scope) if cx.identify_regions => {
                     match scope.data() {
-                        region::ScopeData::Node(id) =>
-                            write!(f, "'{}s", id.as_usize()),
-                        region::ScopeData::CallSite(id) =>
-                            write!(f, "'{}cs", id.as_usize()),
-                        region::ScopeData::Arguments(id) =>
-                            write!(f, "'{}as", id.as_usize()),
-                        region::ScopeData::Destruction(id) =>
-                            write!(f, "'{}ds", id.as_usize()),
-                        region::ScopeData::Remainder(BlockRemainder
-                                                     { block, first_statement_index }) =>
-                            write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()),
+                        region::ScopeData::Node =>
+                            write!(f, "'{}s", scope.item_local_id().as_usize()),
+                        region::ScopeData::CallSite =>
+                            write!(f, "'{}cs", scope.item_local_id().as_usize()),
+                        region::ScopeData::Arguments =>
+                            write!(f, "'{}as", scope.item_local_id().as_usize()),
+                        region::ScopeData::Destruction =>
+                            write!(f, "'{}ds", scope.item_local_id().as_usize()),
+                        region::ScopeData::Remainder(first_statement_index) => write!(
+                            f,
+                            "'{}_{}rs",
+                            scope.item_local_id().as_usize(),
+                            first_statement_index.index()
+                        ),
                     }
                 }
                 ty::ReVar(region_vid) if cx.identify_regions => {
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 186bc6d43cc..2f11fea46d6 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -72,7 +72,8 @@ macro_rules! newtype_index {
         newtype_index!(
             // Leave out derives marker so we can use its absence to ensure it comes first
             @type         [$name]
-            @max          [::std::u32::MAX - 1]
+            // shave off 256 indices at the end to allow space for packing these indices into enums
+            @max          [0xFFFF_FF00]
             @vis          [$v]
             @debug_format ["{}"]);
     );
@@ -82,7 +83,8 @@ macro_rules! newtype_index {
         newtype_index!(
             // Leave out derives marker so we can use its absence to ensure it comes first
             @type         [$name]
-            @max          [::std::u32::MAX - 1]
+            // shave off 256 indices at the end to allow space for packing these indices into enums
+            @max          [0xFFFF_FF00]
             @vis          [$v]
             @debug_format ["{}"]
                           $($tokens)+);
@@ -97,6 +99,7 @@ macro_rules! newtype_index {
      @vis          [$v:vis]
      @debug_format [$debug_format:tt]) => (
         #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
+        #[rustc_layout_scalar_valid_range_end($max)]
         $v struct $type {
             private: u32
         }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 1ed8289d441..d46b0813ca7 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -51,7 +51,7 @@ impl<'tcx> CFG<'tcx> {
                                              source_info: SourceInfo,
                                              region_scope: region::Scope) {
         if tcx.emit_end_regions() {
-            if let region::ScopeData::CallSite(_) = region_scope.data() {
+            if let region::ScopeData::CallSite = region_scope.data() {
                 // The CallSite scope (aka the root scope) is sort of weird, in that it is
                 // supposed to "separate" the "interior" and "exterior" of a closure. Being
                 // that, it is not really a part of the region hierarchy, but for some
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 38e0854bcd6..1406183955b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -566,7 +566,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // We want `scopes[1]`, which is the `ParameterScope`.
         assert!(self.scopes.len() >= 2);
         assert!(match self.scopes[1].region_scope.data() {
-            region::ScopeData::Arguments(_) => true,
+            region::ScopeData::Arguments => true,
             _ => false,
         });
         self.scopes[1].region_scope
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 85a9734a601..b0a60fedfbb 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -11,7 +11,7 @@
 use hair::*;
 use hair::cx::Cx;
 use hair::cx::to_ref::ToRef;
-use rustc::middle::region::{self, BlockRemainder};
+use rustc::middle::region;
 use rustc::hir;
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -71,10 +71,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         // ignore for purposes of the MIR
                     }
                     hir::DeclKind::Local(ref local) => {
-                        let remainder_scope = region::Scope::Remainder(BlockRemainder {
-                            block: block_id,
-                            first_statement_index: region::FirstStatementIndex::new(index),
-                        });
+                        let remainder_scope = region::Scope::Remainder(
+                            block_id,
+                            region::FirstStatementIndex::new(index),
+                        );
 
                         let mut pattern = cx.pattern_from_hir(&local.pat);
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 461285ff9bc..8bb93d09a2a 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -340,7 +340,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
         let field = field.try_into().unwrap();
         let field_layout = op.layout.field(self, field)?;
-        if field_layout.size.bytes() == 0 {
+        if field_layout.is_zst() {
             let val = Value::Scalar(Scalar::zst().into());
             return Ok(OpTy { op: Operand::Immediate(val), layout: field_layout });
         }
@@ -397,9 +397,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Field(field, _) => self.operand_field(base, field.index() as u64)?,
             Downcast(_, variant) => self.operand_downcast(base, variant)?,
             Deref => self.deref_operand(base)?.into(),
-            // The rest should only occur as mplace, we do not use Immediates for types
-            // allowing such operations.  This matches place_projection forcing an allocation.
-            Subslice { .. } | ConstantIndex { .. } | Index(_) => {
+            Subslice { .. } | ConstantIndex { .. } | Index(_) => if base.layout.is_zst() {
+                OpTy {
+                    op: Operand::Immediate(Value::Scalar(Scalar::zst().into())),
+                    // the actual index doesn't matter, so we just pick a convenient one like 0
+                    layout: base.layout.field(self, 0)?,
+                }
+            } else {
+                // The rest should only occur as mplace, we do not use Immediates for types
+                // allowing such operations.  This matches place_projection forcing an allocation.
                 let mplace = base.to_mem_place();
                 self.mplace_projection(mplace, proj_elem)?.into()
             }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index e71de0001fb..1594755b4ab 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -29,6 +29,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(exhaustive_patterns)]
 #![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(rustc_attrs)]
+#![cfg_attr(stage0, feature(attr_literals))]
 #![feature(never_type)]
 #![feature(specialization)]
 #![feature(try_trait)]
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 7d9139df415..25a7ff9cd3f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -22,7 +22,7 @@ use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use {resolve_error, resolve_struct_error, ResolutionError};
 
 use rustc::hir::def::*;
-use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::ty;
 use rustc::middle::cstore::CrateStore;
 use rustc_metadata::cstore::LoadedMacro;
@@ -769,7 +769,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         let def_id = self.macro_defs[&expansion];
         if let Some(id) = self.definitions.as_local_node_id(def_id) {
             self.local_macro_def_scopes[&id]
-        } else if def_id.krate == BUILTIN_MACROS_CRATE {
+        } else if def_id.krate == CrateNum::BuiltinMacros {
             self.injected_crate.unwrap_or(self.graph_root)
         } else {
             let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index f687e022a41..f8b5f891579 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -14,8 +14,8 @@ use ModuleOrUniformRoot;
 use Namespace::{self, TypeNS, MacroNS};
 use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
 use resolve_imports::ImportResolver;
-use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
-                         DefIndexAddressSpace};
+use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex,
+                         CrateNum, DefIndexAddressSpace};
 use rustc::hir::def::{Def, NonMacroAttrKind};
 use rustc::hir::map::{self, DefCollector};
 use rustc::{ty, lint};
@@ -218,7 +218,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
 
     fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
         let def_id = DefId {
-            krate: BUILTIN_MACROS_CRATE,
+            krate: CrateNum::BuiltinMacros,
             index: DefIndex::from_array_index(self.macro_map.len(),
                                               DefIndexAddressSpace::Low),
         };
@@ -352,7 +352,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
             self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
                                                             normal_module_def_id);
             invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
-            invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
+            invoc.expansion_data.mark.set_is_builtin(def_id.krate == CrateNum::BuiltinMacros);
         }
 
         Ok(Some(ext))
@@ -1135,7 +1135,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         };
 
         // Plugin-based syntax extensions are exempt from this check
-        if krate == BUILTIN_MACROS_CRATE { return; }
+        if krate == CrateNum::BuiltinMacros { return; }
 
         let ext = binding.get_macro(self);
 
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index 2d5c98ff0ed..882579c5710 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -64,11 +64,11 @@ fn main() {
 //     bb0: {
 //         Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
 //         StorageLive(_3);
-//         Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))), [(*_2): i32]);
+//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
 //         _3 = &ReErased (*_2);
-//         Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })) (imm)]);
+//         Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
 //         _0 = (*_3);
-//         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })));
+//         EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
 //         StorageDead(_3);
 //         return;
 //     }
diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs
index 72ec9ce400f..07f5b2aa84b 100644
--- a/src/test/mir-opt/validate_3.rs
+++ b/src/test/mir-opt/validate_3.rs
@@ -48,12 +48,12 @@ fn main() {
 //         StorageLive(_1);
 //         _1 = Test { x: const 0i32 };
 //         StorageLive(_2);
-//         Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))), [_1: Test]);
+//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
 //         _2 = &ReErased _1;
-//         Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]);
+//         Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
 //         _5 = &ReErased ((*_2).0: i32);
 //         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
 //         Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
@@ -68,7 +68,7 @@ fn main() {
 //         StorageDead(_4);
 //         StorageDead(_5);
 //         _0 = ();
-//         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })));
+//         EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }));
 //         StorageDead(_2);
 //         StorageDead(_1);
 //         return;
diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs
new file mode 100644
index 00000000000..08e2c35e072
--- /dev/null
+++ b/src/test/run-pass-fulldeps/newtype_index.rs
@@ -0,0 +1,20 @@
+#![feature(min_const_fn, rustc_attrs, rustc_private, step_trait)]
+
+#[macro_use] extern crate rustc_data_structures;
+extern crate rustc_serialize;
+
+use rustc_data_structures::indexed_vec::Idx;
+
+newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA });
+
+use std::mem::size_of;
+
+fn main() {
+    assert_eq!(size_of::<MyIdx>(), 4);
+    assert_eq!(size_of::<Option<MyIdx>>(), 4);
+    assert_eq!(size_of::<Option<Option<MyIdx>>>(), 4);
+    assert_eq!(size_of::<Option<Option<Option<MyIdx>>>>(), 4);
+    assert_eq!(size_of::<Option<Option<Option<Option<MyIdx>>>>>(), 4);
+    assert_eq!(size_of::<Option<Option<Option<Option<Option<MyIdx>>>>>>(), 4);
+    assert_eq!(size_of::<Option<Option<Option<Option<Option<Option<MyIdx>>>>>>>(), 8);
+}
diff --git a/src/test/ui/consts/const-eval/zst_operand_eval.rs b/src/test/ui/consts/const-eval/zst_operand_eval.rs
new file mode 100644
index 00000000000..d837da1066d
--- /dev/null
+++ b/src/test/ui/consts/const-eval/zst_operand_eval.rs
@@ -0,0 +1,5 @@
+// compile-pass
+
+static ASSERT: () = [()][!(std::mem::size_of::<u32>() == 4) as usize];
+
+fn main() {}