about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-06 10:18:17 +0000
committerbors <bors@rust-lang.org>2018-12-06 10:18:17 +0000
commit128a1fa4e1f85e04f522653bb9bee83ed6523440 (patch)
treecf1bb66e041bed563653ac45ea58bfa863d7518a /src
parent77a6a61f066af3dd693d8527a8a1bf5a446d295c (diff)
parentcb71752f911c47426e208a9f5f1862d4c0e56aa4 (diff)
downloadrust-128a1fa4e1f85e04f522653bb9bee83ed6523440.tar.gz
rust-128a1fa4e1f85e04f522653bb9bee83ed6523440.zip
Auto merge of #55635 - oli-obk:min_const_unsafe_fn, r=nikomatsakis
Allow calling `const unsafe fn` in `const fn` behind a feature gate

cc #55607

r? @Centril
Diffstat (limited to 'src')
-rw-r--r--src/libcore/marker.rs2
-rw-r--r--src/libcore/nonzero.rs17
-rw-r--r--src/libcore/num/mod.rs4
-rw-r--r--src/libcore/ptr.rs14
-rw-r--r--src/librustc/ich/impls_mir.rs3
-rw-r--r--src/librustc/mir/mod.rs9
-rw-r--r--src/librustc/ty/constness.rs18
-rw-r--r--src/librustc_data_structures/indexed_vec.rs32
-rw-r--r--src/librustc_mir/build/mod.rs11
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs255
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs40
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/run-pass-fulldeps/newtype_index.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs24
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr48
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs62
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr97
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs47
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr26
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs43
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr20
-rw-r--r--src/test/ui/unsafe/ranged_ints.rs8
-rw-r--r--src/test/ui/unsafe/ranged_ints.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints2.rs9
-rw-r--r--src/test/ui/unsafe/ranged_ints2.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints2_const.rs20
-rw-r--r--src/test/ui/unsafe/ranged_ints2_const.stderr24
-rw-r--r--src/test/ui/unsafe/ranged_ints3.rs11
-rw-r--r--src/test/ui/unsafe/ranged_ints3.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints3_const.rs21
-rw-r--r--src/test/ui/unsafe/ranged_ints3_const.stderr24
-rw-r--r--src/test/ui/unsafe/ranged_ints4.rs9
-rw-r--r--src/test/ui/unsafe/ranged_ints4.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints4_const.rs19
-rw-r--r--src/test/ui/unsafe/ranged_ints4_const.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.rs11
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.stderr11
38 files changed, 868 insertions, 137 deletions
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 3bcdfabbb24..23f07773f3f 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -596,7 +596,7 @@ mod impls {
 /// This affects, for example, whether a `static` of that type is
 /// placed in read-only static memory or writable static memory.
 #[lang = "freeze"]
-unsafe auto trait Freeze {}
+pub(crate) unsafe auto trait Freeze {}
 
 impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
 unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs
index 436cd1fc057..a89c6ca60cb 100644
--- a/src/libcore/nonzero.rs
+++ b/src/libcore/nonzero.rs
@@ -11,14 +11,23 @@
 //! Exposes the NonZero lang item which provides optimization hints.
 
 use ops::{CoerceUnsized, DispatchFromDyn};
+use marker::Freeze;
 
 /// A wrapper type for raw pointers and integers that will never be
 /// NULL or 0 that might allow certain optimizations.
 #[rustc_layout_scalar_valid_range_start(1)]
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[repr(transparent)]
-pub(crate) struct NonZero<T>(pub(crate) T);
+pub(crate) struct NonZero<T: Freeze>(pub(crate) T);
 
-impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
+// Do not call `T::clone` as theoretically it could turn the field into `0`
+// invalidating `NonZero`'s invariant.
+impl<T: Copy + Freeze> Clone for NonZero<T> {
+    fn clone(&self) -> Self {
+        unsafe { NonZero(self.0) }
+    }
+}
 
-impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
+impl<T: CoerceUnsized<U> + Freeze, U: Freeze> CoerceUnsized<NonZero<U>> for NonZero<T> {}
+
+impl<T: DispatchFromDyn<U> + Freeze, U: Freeze> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 805be431328..7f5d596b220 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -70,7 +70,7 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
                 #[stable(feature = "nonzero", since = "1.28.0")]
                 #[inline]
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
-                    $Ty(NonZero(n))
+                    $Ty(unsafe { NonZero(n) })
                 }
 
                 /// Create a non-zero if the given value is not zero.
@@ -78,7 +78,7 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
                 #[inline]
                 pub fn new(n: $Int) -> Option<Self> {
                     if n != 0 {
-                        Some($Ty(NonZero(n)))
+                        Some($Ty(unsafe { NonZero(n) }))
                     } else {
                         None
                     }
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index d3a74ed2a68..0387708033b 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -2759,7 +2759,7 @@ impl<T: ?Sized> Unique<T> {
     /// Creates a new `Unique` if `ptr` is non-null.
     pub fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
-            Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData })
+            Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData })
         } else {
             None
         }
@@ -2815,14 +2815,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
 #[unstable(feature = "ptr_internals", issue = "0")]
 impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
     fn from(reference: &'a mut T) -> Self {
-        Unique { pointer: NonZero(reference as _), _marker: PhantomData }
+        Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
     }
 }
 
 #[unstable(feature = "ptr_internals", issue = "0")]
 impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
     fn from(reference: &'a T) -> Self {
-        Unique { pointer: NonZero(reference as _), _marker: PhantomData }
+        Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
     }
 }
 
@@ -2895,7 +2895,7 @@ impl<T: ?Sized> NonNull<T> {
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
-        NonNull { pointer: NonZero(ptr as _) }
+        NonNull { pointer: unsafe { NonZero(ptr as _) } }
     }
 
     /// Creates a new `NonNull` if `ptr` is non-null.
@@ -2903,7 +2903,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline]
     pub fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
-            Some(NonNull { pointer: NonZero(ptr as _) })
+            Some(unsafe { Self::new_unchecked(ptr) })
         } else {
             None
         }
@@ -3025,7 +3025,7 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
 impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
     #[inline]
     fn from(reference: &'a mut T) -> Self {
-        NonNull { pointer: NonZero(reference as _) }
+        NonNull { pointer: unsafe { NonZero(reference as _) } }
     }
 }
 
@@ -3033,6 +3033,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
 impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
     #[inline]
     fn from(reference: &'a T) -> Self {
-        NonNull { pointer: NonZero(reference as _) }
+        NonNull { pointer: unsafe { NonZero(reference as _) } }
     }
 }
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index c2987226631..c72887124aa 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -46,7 +46,8 @@ impl_stable_hash_for!(enum mir::BorrowKind {
 
 impl_stable_hash_for!(enum mir::UnsafetyViolationKind {
     General,
-    MinConstFn,
+    GeneralAndConstFn,
+    GatedConstFnCall,
     ExternStatic(lint_node_id),
     BorrowPacked(lint_node_id),
 });
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 8c4a40c00c3..91663557409 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -25,7 +25,7 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::sync::MappedReadGuard;
-use rustc_serialize as serialize;
+use rustc_serialize::{self as serialize};
 use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Formatter, Write};
@@ -2778,8 +2778,11 @@ impl Location {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum UnsafetyViolationKind {
     General,
-    /// unsafety is not allowed at all in min const fn
-    MinConstFn,
+    /// Right now function calls to `const unsafe fn` are only permitted behind a feature gate
+    /// Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations.
+    GatedConstFnCall,
+    /// Permitted in const fn and regular fns
+    GeneralAndConstFn,
     ExternStatic(ast::NodeId),
     BorrowPacked(ast::NodeId),
 }
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index e32913b8905..bc061673995 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -5,7 +5,6 @@ use ty::TyCtxt;
 use syntax_pos::symbol::Symbol;
 use hir::map::blocks::FnLikeNode;
 use syntax::attr;
-use rustc_target::spec::abi;
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     /// Whether the `def_id` counts as const fn in your current crate, considering all active
@@ -40,19 +39,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
 
     /// Returns true if this function must conform to `min_const_fn`
     pub fn is_min_const_fn(self, def_id: DefId) -> bool {
+        // Bail out if the signature doesn't contain `const`
+        if !self.is_const_fn_raw(def_id) {
+            return false;
+        }
+
         if self.features().staged_api {
-            // some intrinsics are waved through if called inside the
-            // standard library. Users never need to call them directly
-            if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
-                assert!(!self.is_const_fn(def_id));
-                match &self.item_name(def_id).as_str()[..] {
-                    | "size_of"
-                    | "min_align_of"
-                    | "needs_drop"
-                    => return true,
-                    _ => {},
-                }
-            }
             // in order for a libstd function to be considered min_const_fn
             // it needs to be stable and have no `rustc_const_unstable` attribute
             match self.lookup_stability(def_id) {
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index a59bf9d530c..6522dbe1179 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -98,12 +98,18 @@ macro_rules! newtype_index {
      @max          [$max:expr]
      @vis          [$v:vis]
      @debug_format [$debug_format:tt]) => (
-        #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
+        #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
         #[rustc_layout_scalar_valid_range_end($max)]
         $v struct $type {
             private: u32
         }
 
+        impl Clone for $type {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
         impl $type {
             $v const MAX_AS_U32: u32 = $max;
 
@@ -145,7 +151,7 @@ macro_rules! newtype_index {
 
             #[inline]
             $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
-                $type { private: value }
+                unsafe { $type { private: value } }
             }
 
             /// Extract value of this index as an integer.
@@ -328,12 +334,13 @@ macro_rules! newtype_index {
                    derive [$($derives:ident,)+]
                    $($tokens:tt)*) => (
         newtype_index!(
-            @derives      [$($derives,)+ RustcDecodable, RustcEncodable,]
+            @derives      [$($derives,)+ RustcEncodable,]
             @type         [$type]
             @max          [$max]
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
+        newtype_index!(@decodable $type);
     );
 
     // The case where no derives are added, but encodable is overridden. Don't
@@ -360,12 +367,29 @@ macro_rules! newtype_index {
      @debug_format [$debug_format:tt]
                    $($tokens:tt)*) => (
         newtype_index!(
-            @derives      [RustcDecodable, RustcEncodable,]
+            @derives      [RustcEncodable,]
             @type         [$type]
             @max          [$max]
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
+        newtype_index!(@decodable $type);
+    );
+
+    (@decodable $type:ident) => (
+        impl $type {
+            fn __decodable__impl__hack() {
+                mod __more_hacks_because__self_doesnt_work_in_functions {
+                    extern crate serialize;
+                    use self::serialize::{Decodable, Decoder};
+                    impl Decodable for super::$type {
+                        fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+                            d.read_u32().map(Self::from)
+                        }
+                    }
+                }
+            }
+        }
     );
 
     // Rewrite final without comma to one that includes comma
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index d95a74be776..90a204ce00d 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -91,8 +91,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
             // types/lifetimes replaced)
             let fn_hir_id = tcx.hir.node_to_hir_id(id);
             let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone();
+            let fn_def_id = tcx.hir.local_def_id(id);
 
-            let ty = tcx.type_of(tcx.hir.local_def_id(id));
+            let ty = tcx.type_of(fn_def_id);
             let mut abi = fn_sig.abi;
             let implicit_argument = match ty.sty {
                 ty::Closure(..) => {
@@ -108,9 +109,15 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
                 _ => None,
             };
 
-            // FIXME: safety in closures
             let safety = match fn_sig.unsafety {
                 hir::Unsafety::Normal => Safety::Safe,
+                hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => {
+                    // As specified in #55607, a `const unsafe fn` differs
+                    // from an `unsafe fn` in that its body is still considered
+                    // safe code by default.
+                    assert!(implicit_argument.is_none());
+                    Safety::Safe
+                },
                 hir::Unsafety::Unsafe => Safety::FnUnsafe,
             };
 
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 3404772f825..75f8045cfae 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -23,6 +23,9 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
 
 use syntax::ast;
 use syntax::symbol::Symbol;
+use syntax::feature_gate::{emit_feature_err, GateIssue};
+
+use std::ops::Bound;
 
 use util;
 
@@ -34,6 +37,7 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
     source_info: SourceInfo,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
+    /// mark an `unsafe` block as used, so we don't lint it
     used_unsafe: FxHashSet<ast::NodeId>,
     inherited_blocks: Vec<(ast::NodeId, bool)>,
 }
@@ -93,7 +97,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 if let hir::Unsafety::Unsafe = sig.unsafety() {
                     self.require_unsafe("call to unsafe function",
                         "consult the function's documentation for information on how to avoid \
-                         undefined behavior")
+                         undefined behavior", UnsafetyViolationKind::GatedConstFnCall)
                 }
             }
         }
@@ -121,7 +125,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
 
             StatementKind::InlineAsm { .. } => {
                 self.require_unsafe("use of inline assembly",
-                    "inline assembly is entirely unchecked and can cause undefined behavior")
+                    "inline assembly is entirely unchecked and can cause undefined behavior",
+                    UnsafetyViolationKind::General)
             },
         }
         self.super_statement(block, statement, location);
@@ -134,8 +139,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
         if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue {
             match aggregate {
                 &AggregateKind::Array(..) |
-                &AggregateKind::Tuple |
-                &AggregateKind::Adt(..) => {}
+                &AggregateKind::Tuple => {}
+                &AggregateKind::Adt(ref def, ..) => {
+                    match self.tcx.layout_scalar_valid_range(def.did) {
+                        (Bound::Unbounded, Bound::Unbounded) => {},
+                        _ => self.require_unsafe(
+                            "initializing type with `rustc_layout_scalar_valid_range` attr",
+                            "initializing a layout restricted type's field with a value outside \
+                            the valid range is undefined behavior",
+                            UnsafetyViolationKind::GeneralAndConstFn,
+                        ),
+                    }
+                }
                 &AggregateKind::Closure(def_id, _) |
                 &AggregateKind::Generator(def_id, _, _) => {
                     let UnsafetyCheckResult {
@@ -152,28 +167,43 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     place: &Place<'tcx>,
                     context: PlaceContext<'tcx>,
                     location: Location) {
-        if context.is_borrow() {
-            if util::is_disaligned(self.tcx, self.mir, self.param_env, place) {
-                let source_info = self.source_info;
-                let lint_root =
-                    self.source_scope_local_data[source_info.scope].lint_root;
-                self.register_violations(&[UnsafetyViolation {
-                    source_info,
-                    description: Symbol::intern("borrow of packed field").as_interned_str(),
-                    details:
-                        Symbol::intern("fields of packed structs might be misaligned: \
-                                        dereferencing a misaligned pointer or even just creating a \
-                                        misaligned reference is undefined behavior")
-                            .as_interned_str(),
-                    kind: UnsafetyViolationKind::BorrowPacked(lint_root)
-                }], &[]);
-            }
-        }
-
         match place {
             &Place::Projection(box Projection {
                 ref base, ref elem
             }) => {
+                if context.is_borrow() {
+                    if util::is_disaligned(self.tcx, self.mir, self.param_env, place) {
+                        let source_info = self.source_info;
+                        let lint_root =
+                            self.source_scope_local_data[source_info.scope].lint_root;
+                        self.register_violations(&[UnsafetyViolation {
+                            source_info,
+                            description: Symbol::intern("borrow of packed field").as_interned_str(),
+                            details:
+                                Symbol::intern("fields of packed structs might be misaligned: \
+                                                dereferencing a misaligned pointer or even just \
+                                                creating a misaligned reference is undefined \
+                                                behavior")
+                                    .as_interned_str(),
+                            kind: UnsafetyViolationKind::BorrowPacked(lint_root)
+                        }], &[]);
+                    }
+                }
+                let is_borrow_of_interior_mut = context.is_borrow() && !base
+                    .ty(self.mir, self.tcx)
+                    .to_ty(self.tcx)
+                    .is_freeze(self.tcx, self.param_env, self.source_info.span);
+                // prevent
+                // * `&mut x.field`
+                // * `x.field = y;`
+                // * `&x.field` if `field`'s type has interior mutability
+                // because either of these would allow modifying the layout constrained field and
+                // insert values that violate the layout constraints.
+                if context.is_mutating_use() || is_borrow_of_interior_mut {
+                    self.check_mut_borrowing_layout_constrained_field(
+                        place, context.is_mutating_use(),
+                    );
+                }
                 let old_source_info = self.source_info;
                 if let &Place::Local(local) = base {
                     if self.mir.local_decls[local].internal {
@@ -189,7 +219,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                         self.require_unsafe("dereference of raw pointer",
                             "raw pointers may be NULL, dangling or unaligned; they can violate \
                              aliasing rules and cause data races: all of these are undefined \
-                             behavior")
+                             behavior", UnsafetyViolationKind::General)
                     }
                     ty::Adt(adt, _) => {
                         if adt.is_union() {
@@ -212,14 +242,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                                         "assignment to non-`Copy` union field",
                                         "the previous content of the field will be dropped, which \
                                          causes undefined behavior if the field was not properly \
-                                         initialized")
+                                         initialized", UnsafetyViolationKind::General)
                                 } else {
                                     // write to non-move union, safe
                                 }
                             } else {
                                 self.require_unsafe("access to union field",
                                     "the field may not be properly initialized: using \
-                                     uninitialized data will cause undefined behavior")
+                                     uninitialized data will cause undefined behavior",
+                                     UnsafetyViolationKind::General)
                             }
                         }
                     }
@@ -237,7 +268,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
                     self.require_unsafe("use of mutable static",
                         "mutable statics can be mutated by multiple threads: aliasing violations \
-                         or data races will cause undefined behavior");
+                         or data races will cause undefined behavior",
+                         UnsafetyViolationKind::General);
                 } else if self.tcx.is_foreign_item(def_id) {
                     let source_info = self.source_info;
                     let lint_root =
@@ -260,45 +292,96 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn require_unsafe(&mut self,
-                      description: &'static str,
-                      details: &'static str)
-    {
+    fn require_unsafe(
+        &mut self,
+        description: &'static str,
+        details: &'static str,
+        kind: UnsafetyViolationKind,
+    ) {
         let source_info = self.source_info;
         self.register_violations(&[UnsafetyViolation {
             source_info,
             description: Symbol::intern(description).as_interned_str(),
             details: Symbol::intern(details).as_interned_str(),
-            kind: UnsafetyViolationKind::General,
+            kind,
         }], &[]);
     }
 
     fn register_violations(&mut self,
                            violations: &[UnsafetyViolation],
                            unsafe_blocks: &[(ast::NodeId, bool)]) {
-        if self.min_const_fn {
-            for violation in violations {
-                let mut violation = violation.clone();
-                violation.kind = UnsafetyViolationKind::MinConstFn;
-                if !self.violations.contains(&violation) {
-                    self.violations.push(violation)
-                }
-            }
-        }
-        let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety {
-            Safety::Safe => {
+        let safety = self.source_scope_local_data[self.source_info.scope].safety;
+        let within_unsafe = match (safety, self.min_const_fn) {
+            // Erring on the safe side, pun intended
+            (Safety::BuiltinUnsafe, true) |
+            // mir building encodes const fn bodies as safe, even for `const unsafe fn`
+            (Safety::FnUnsafe, true) => bug!("const unsafe fn body treated as inherently unsafe"),
+            // `unsafe` blocks are required in safe code
+            (Safety::Safe, _) => {
                 for violation in violations {
-                    if !self.violations.contains(violation) {
-                        self.violations.push(violation.clone())
+                    let mut violation = violation.clone();
+                    match violation.kind {
+                        UnsafetyViolationKind::GeneralAndConstFn |
+                        UnsafetyViolationKind::General => {},
+                        UnsafetyViolationKind::BorrowPacked(_) |
+                        UnsafetyViolationKind::ExternStatic(_) => if self.min_const_fn {
+                            // const fns don't need to be backwards compatible and can
+                            // emit these violations as a hard error instead of a backwards
+                            // compat lint
+                            violation.kind = UnsafetyViolationKind::General;
+                        },
+                        UnsafetyViolationKind::GatedConstFnCall => {
+                            // safe code can't call unsafe const fns, this `UnsafetyViolationKind`
+                            // is only relevant for `Safety::ExplicitUnsafe` in `unsafe const fn`s
+                            violation.kind = UnsafetyViolationKind::General;
+                        }
+                    }
+                    if !self.violations.contains(&violation) {
+                        self.violations.push(violation)
                     }
                 }
                 false
             }
-            Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
-            Safety::ExplicitUnsafe(node_id) => {
+            // regular `unsafe` function bodies allow unsafe without additional unsafe blocks
+            (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true,
+            (Safety::ExplicitUnsafe(node_id), _) => {
+                // mark unsafe block as used if there are any unsafe operations inside
                 if !violations.is_empty() {
                     self.used_unsafe.insert(node_id);
                 }
+                // only some unsafety is allowed in const fn
+                if self.min_const_fn {
+                    let min_const_unsafe_fn = self.tcx.features().min_const_unsafe_fn;
+                    for violation in violations {
+                        match violation.kind {
+                            UnsafetyViolationKind::GatedConstFnCall if min_const_unsafe_fn => {
+                                // these function calls to unsafe functions are allowed
+                                // if `#![feature(min_const_unsafe_fn)]` is active
+                            },
+                            UnsafetyViolationKind::GatedConstFnCall => {
+                                // without the feature gate, we report errors
+                                if !self.violations.contains(&violation) {
+                                    self.violations.push(violation.clone())
+                                }
+                            }
+                            // these unsafe things are stable in const fn
+                            UnsafetyViolationKind::GeneralAndConstFn => {},
+                            // these things are forbidden in const fns
+                            UnsafetyViolationKind::General |
+                            UnsafetyViolationKind::BorrowPacked(_) |
+                            UnsafetyViolationKind::ExternStatic(_) => {
+                                let mut violation = violation.clone();
+                                // const fns don't need to be backwards compatible and can
+                                // emit these violations as a hard error instead of a backwards
+                                // compat lint
+                                violation.kind = UnsafetyViolationKind::General;
+                                if !self.violations.contains(&violation) {
+                                    self.violations.push(violation)
+                                }
+                            },
+                        }
+                    }
+                }
                 true
             }
         };
@@ -306,6 +389,53 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
             (node_id, is_used && !within_unsafe)
         }));
     }
+    fn check_mut_borrowing_layout_constrained_field(
+        &mut self,
+        mut place: &Place<'tcx>,
+        is_mut_use: bool,
+    ) {
+        while let &Place::Projection(box Projection {
+            ref base, ref elem
+        }) = place {
+            match *elem {
+                ProjectionElem::Field(..) => {
+                    let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx);
+                    match ty.sty {
+                        ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
+                            (Bound::Unbounded, Bound::Unbounded) => {},
+                            _ => {
+                                let (description, details) = if is_mut_use {
+                                    (
+                                        "mutation of layout constrained field",
+                                        "mutating layout constrained fields cannot statically be \
+                                        checked for valid values",
+                                    )
+                                } else {
+                                    (
+                                        "borrow of layout constrained field with interior \
+                                        mutability",
+                                        "references to fields of layout constrained fields \
+                                        lose the constraints. Coupled with interior mutability, \
+                                        the field can be changed to invalid values",
+                                    )
+                                };
+                                let source_info = self.source_info;
+                                self.register_violations(&[UnsafetyViolation {
+                                    source_info,
+                                    description: Symbol::intern(description).as_interned_str(),
+                                    details: Symbol::intern(details).as_interned_str(),
+                                    kind: UnsafetyViolationKind::GeneralAndConstFn,
+                                }], &[]);
+                            }
+                        },
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+            place = base;
+        }
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -384,7 +514,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 
     let param_env = tcx.param_env(def_id);
     let mut checker = UnsafetyChecker::new(
-        tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id),
+        tcx.is_min_const_fn(def_id),
         mir, source_scope_local_data, tcx, param_env);
     checker.visit_mir(mir);
 
@@ -486,6 +616,22 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
     } in violations.iter() {
         // Report an error.
         match kind {
+            UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => {
+                let mut err = tcx.sess.struct_span_err(
+                    source_info.span,
+                    &format!("{} is unsafe and unsafe operations \
+                            are not allowed in const fn", description));
+                err.span_label(source_info.span, &description.as_str()[..])
+                    .note(&details.as_str()[..]);
+                if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe {
+                    err.note(
+                        "unsafe action within a `const unsafe fn` still require an `unsafe` \
+                        block in contrast to regular `unsafe fn`."
+                    );
+                }
+                err.emit();
+            }
+            UnsafetyViolationKind::GeneralAndConstFn |
             UnsafetyViolationKind::General => {
                 struct_span_err!(
                     tcx.sess, source_info.span, E0133,
@@ -494,14 +640,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
                     .note(&details.as_str()[..])
                     .emit();
             }
-            UnsafetyViolationKind::MinConstFn => {
-                tcx.sess.struct_span_err(
+            UnsafetyViolationKind::GatedConstFnCall => {
+                emit_feature_err(
+                    &tcx.sess.parse_sess,
+                    "min_const_unsafe_fn",
                     source_info.span,
-                    &format!("{} is unsafe and unsafe operations \
-                            are not allowed in const fn", description))
-                    .span_label(source_info.span, &description.as_str()[..])
-                    .note(&details.as_str()[..])
-                    .emit();
+                    GateIssue::Language,
+                    "calls to `const unsafe fn` in const fns are unstable",
+                );
+
             }
             UnsafetyViolationKind::ExternStatic(lint_node_id) => {
                 tcx.lint_node_note(SAFE_EXTERN_STATICS,
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 13e134ba859..3c1b9dbd91f 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -2,6 +2,7 @@ use rustc::hir::def_id::DefId;
 use rustc::hir;
 use rustc::mir::*;
 use rustc::ty::{self, Predicate, TyCtxt};
+use rustc_target::spec::abi;
 use std::borrow::Cow;
 use syntax_pos::Span;
 
@@ -338,19 +339,40 @@ fn check_terminator(
         } => {
             let fn_ty = func.ty(mir, tcx);
             if let ty::FnDef(def_id, _) = fn_ty.sty {
-                if tcx.is_min_const_fn(def_id) {
-                    check_operand(tcx, mir, func, span)?;
 
-                    for arg in args {
-                        check_operand(tcx, mir, arg, span)?;
-                    }
-                    Ok(())
-                } else {
-                    Err((
+                // some intrinsics are waved through if called inside the
+                // standard library. Users never need to call them directly
+                match tcx.fn_sig(def_id).abi() {
+                    abi::Abi::RustIntrinsic => match &tcx.item_name(def_id).as_str()[..] {
+                        | "size_of"
+                        | "min_align_of"
+                        | "needs_drop"
+                        => {},
+                        _ => return Err((
+                            span,
+                            "can only call a curated list of intrinsics in `min_const_fn`".into(),
+                        )),
+                    },
+                    abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
+                    abi::Abi::Rust => return Err((
                         span,
                         "can only call other `min_const_fn` within a `min_const_fn`".into(),
-                    ))
+                    )),
+                    abi => return Err((
+                        span,
+                        format!(
+                            "cannot call functions with `{}` abi in `min_const_fn`",
+                            abi,
+                        ).into(),
+                    )),
+                }
+
+                check_operand(tcx, mir, func, span)?;
+
+                for arg in args {
+                    check_operand(tcx, mir, arg, span)?;
                 }
+                Ok(())
             } else {
                 Err((span, "can only call other const fns within const fn".into()))
             }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index fac7ff2bf34..bfdc75378d5 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -492,6 +492,9 @@ declare_features! (
 
     // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`.
     (active, extern_crate_self, "1.31.0", Some(56409), None),
+
+    // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
+    (active, min_const_unsafe_fn, "1.31.0", Some(55607), None),
 );
 
 declare_features! (
diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs
index 3cd622a33b1..0fd7ccd55fb 100644
--- a/src/test/run-pass-fulldeps/newtype_index.rs
+++ b/src/test/run-pass-fulldeps/newtype_index.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_attrs, rustc_private, step_trait)]
+#![feature(rustc_attrs, rustc_private, step_trait, min_const_unsafe_fn)]
 
 #[macro_use] extern crate rustc_data_structures;
 extern crate rustc_serialize;
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index 0dba3a7de53..43ca9e75393 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -78,9 +78,9 @@ const fn i32_ops2(c: i32, d: i32) -> bool { c < d }
 const fn i32_ops3(c: i32, d: i32) -> bool { c != d }
 const fn i32_ops4(c: i32, d: i32) -> i32 { c + d }
 const fn char_cast(u: u8) -> char { u as char }
-const unsafe fn foo4() -> i32 { 42 }
-const unsafe fn foo5<T>() -> *const T { 0 as *const T }
-const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+const unsafe fn ret_i32_no_unsafe() -> i32 { 42 }
+const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { 0 as *const T }
+const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { 0 as *mut T }
 
 // not ok
 const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
index 67332c6d2cf..f11b43dcd86 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
@@ -8,23 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// gate-test-min_const_unsafe_fn
+
 // ok
-const unsafe fn foo4() -> i32 { 42 }
-const unsafe fn foo5<T>() -> *const T { 0 as *const T }
-const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+const unsafe fn ret_i32_no_unsafe() -> i32 { 42 }
+const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { 0 as *const T }
+const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { 0 as *mut T }
 const fn no_unsafe() { unsafe {} }
 
 // not ok
-const fn foo8() -> i32 {
-    unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+const fn call_unsafe_const_fn() -> i32 {
+    unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable
 }
-const fn foo9() -> *const String {
-    unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
+const fn call_unsafe_generic_const_fn() -> *const String {
+    unsafe { ret_null_ptr_no_unsafe::<String>() }
+    //~^ ERROR calls to `const unsafe fn` in const fns are unstable
 }
-const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
-    unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
+const fn call_unsafe_generic_cell_const_fn() -> *const Vec<std::cell::Cell<u32>> {
+    unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() }
+    //~^ ERROR calls to `const unsafe fn` in const fns
 }
-const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
 //~^ dereferencing raw pointers in constant functions
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr
index 8cff0d491d8..922a7883b9f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr
@@ -1,58 +1,60 @@
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
-  --> $DIR/min_const_fn_unsafe.rs:27:51
+  --> $DIR/min_const_fn_unsafe.rs:31:59
    |
-LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
-   |                                                   ^^
+LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                           ^^
    |
    = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
 
 error[E0658]: unions in const fn are unstable (see issue #51909)
-  --> $DIR/min_const_fn_unsafe.rs:34:5
+  --> $DIR/min_const_fn_unsafe.rs:38:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^
    |
    = help: add #![feature(const_fn_union)] to the crate attributes to enable
 
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:19:14
+error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607)
+  --> $DIR/min_const_fn_unsafe.rs:21:14
    |
-LL |     unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
-   |              ^^^^^^ call to unsafe function
+LL |     unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable
+   |              ^^^^^^^^^^^^^^^^^^^
    |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:22:14
+error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607)
+  --> $DIR/min_const_fn_unsafe.rs:24:14
    |
-LL |     unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
-   |              ^^^^^^^^^^^^^^^^ call to unsafe function
+LL |     unsafe { ret_null_ptr_no_unsafe::<String>() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
-error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:25:14
+error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607)
+  --> $DIR/min_const_fn_unsafe.rs:28:14
    |
-LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+LL |     unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
 error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:27:51
+  --> $DIR/min_const_fn_unsafe.rs:31:59
    |
-LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
-   |                                                   ^^ dereference of raw pointer
+LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                           ^^ dereference of raw pointer
    |
    = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
 
 error: access to union field is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:34:5
+  --> $DIR/min_const_fn_unsafe.rs:38:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs
new file mode 100644
index 00000000000..8a6884bc6b9
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs
@@ -0,0 +1,62 @@
+// Copyright 2018 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.
+
+#![feature(min_const_unsafe_fn)]
+
+// ok
+const unsafe fn foo4() -> i32 { 42 }
+const unsafe fn foo5<T>() -> *const T { 0 as *const T }
+const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+const fn no_unsafe() { unsafe {} }
+
+const fn foo8() -> i32 {
+    unsafe { foo4() }
+}
+const fn foo9() -> *const String {
+    unsafe { foo5::<String>() }
+}
+const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
+    unsafe { foo6::<Vec<std::cell::Cell<u32>>>() }
+}
+const unsafe fn foo8_3() -> i32 {
+    unsafe { foo4() }
+}
+const unsafe fn foo9_3() -> *const String {
+    unsafe { foo5::<String>() }
+}
+const unsafe fn foo10_3() -> *const Vec<std::cell::Cell<u32>> {
+    unsafe { foo6::<Vec<std::cell::Cell<u32>>>() }
+}
+// not ok
+const unsafe fn foo8_2() -> i32 {
+    foo4() //~ ERROR not allowed in const fn
+}
+const unsafe fn foo9_2() -> *const String {
+    foo5::<String>() //~ ERROR not allowed in const fn
+}
+const unsafe fn foo10_2() -> *const Vec<std::cell::Cell<u32>> {
+    foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn
+}
+const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+//~^ dereferencing raw pointers in constant functions
+
+const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
+//~^ dereferencing raw pointers in constant functions
+
+const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+//~^ dereferencing raw pointers in constant functions
+
+fn main() {}
+
+const unsafe fn no_union() {
+    union Foo { x: (), y: () }
+    Foo { x: () }.y //~ ERROR not allowed in const fn
+    //~^ unions in const fn
+}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr
new file mode 100644
index 00000000000..20c75afbe63
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr
@@ -0,0 +1,97 @@
+error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51
+   |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                   ^^
+   |
+   = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60
+   |
+LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
+   |                                                            ^^^
+   |
+   = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62
+   |
+LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+   |                                                              ^^^
+   |
+   = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error[E0658]: unions in const fn are unstable (see issue #51909)
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5
+   |
+LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_fn_union)] to the crate attributes to enable
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:39:5
+   |
+LL |     foo4() //~ ERROR not allowed in const fn
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5
+   |
+LL |     foo5::<String>() //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5
+   |
+LL |     foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51
+   |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                   ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60
+   |
+LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn
+   |                                                            ^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62
+   |
+LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed
+   |                                                              ^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: access to union field is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5
+   |
+LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+   = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`.
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
new file mode 100644
index 00000000000..f559c23ff0f
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 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.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(min_const_unsafe_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const unsafe fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const unsafe fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// conformity is required, even with `const_fn` feature gate
+const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
+
+// check whether this function cannot be called even with the feature gate active
+#[unstable(feature = "foo2", issue="0")]
+const unsafe fn foo2_gated() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
new file mode 100644
index 00000000000..37be2889173
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -0,0 +1,26 @@
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41
+   |
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
+   |                                         ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42
+   |
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
+   |                                          ^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33
+   |
+LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
+   |                                 ^^^^^^^^^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48
+   |
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
+   |                                                ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
new file mode 100644
index 00000000000..131bc97c85a
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 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.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(min_const_unsafe_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+
+// check whether this function cannot be called even with the feature gate active
+#[unstable(feature = "foo2", issue="0")]
+const fn foo2_gated() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
new file mode 100644
index 00000000000..0b58dc1294b
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -0,0 +1,20 @@
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32
+   |
+LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+   |                                ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33
+   |
+LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+   |                                 ^^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39
+   |
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+   |                                       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs
new file mode 100644
index 00000000000..0fa2da917e9
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints.rs
@@ -0,0 +1,8 @@
+#![feature(rustc_attrs)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {
+    let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr
+}
diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr
new file mode 100644
index 00000000000..f59a930b5a9
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints.rs:7:14
+   |
+LL |     let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr
+   |              ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs
new file mode 100644
index 00000000000..68ba120b279
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints2.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {
+    let mut x = unsafe { NonZero(1) };
+    let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe
+}
diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr
new file mode 100644
index 00000000000..ae63f47ed74
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints2.stderr
@@ -0,0 +1,11 @@
+error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints2.rs:8:13
+   |
+LL |     let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe
+   |             ^^^^^^^^ mutation of layout constrained field
+   |
+   = note: mutating layout constrained fields cannot statically be checked for valid values
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs
new file mode 100644
index 00000000000..a61e3329bdc
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints2_const.rs
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs, const_let, const_fn)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {
+}
+
+const fn foo() -> NonZero<u32> {
+    let mut x = unsafe { NonZero(1) };
+    let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable
+    //~^ ERROR mutation of layout constrained field is unsafe
+    unsafe { NonZero(1) }
+}
+
+const fn bar() -> NonZero<u32> {
+    let mut x = unsafe { NonZero(1) };
+    let y = unsafe { &mut x.0 }; //~ ERROR references in constant functions may only refer to immut
+    unsafe { NonZero(1) }
+}
diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr
new file mode 100644
index 00000000000..f79792ffba9
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints2_const.stderr
@@ -0,0 +1,24 @@
+error[E0017]: references in constant functions may only refer to immutable values
+  --> $DIR/ranged_ints2_const.rs:11:13
+   |
+LL |     let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable
+   |             ^^^^^^^^ constant functions require immutable values
+
+error[E0017]: references in constant functions may only refer to immutable values
+  --> $DIR/ranged_ints2_const.rs:18:22
+   |
+LL |     let y = unsafe { &mut x.0 }; //~ ERROR references in constant functions may only refer to immut
+   |                      ^^^^^^^^ constant functions require immutable values
+
+error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints2_const.rs:11:13
+   |
+LL |     let y = &mut x.0; //~ ERROR references in constant functions may only refer to immutable
+   |             ^^^^^^^^ mutation of layout constrained field
+   |
+   = note: mutating layout constrained fields cannot statically be checked for valid values
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0017, E0133.
+For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs
new file mode 100644
index 00000000000..47d67fac678
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints3.rs
@@ -0,0 +1,11 @@
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {
+    let mut x = unsafe { NonZero(Cell::new(1)) };
+    let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability
+}
diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr
new file mode 100644
index 00000000000..311a058fdb0
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints3.stderr
@@ -0,0 +1,11 @@
+error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints3.rs:10:13
+   |
+LL |     let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability
+   |             ^^^^ borrow of layout constrained field with interior mutability
+   |
+   = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints3_const.rs b/src/test/ui/unsafe/ranged_ints3_const.rs
new file mode 100644
index 00000000000..6497b611224
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints3_const.rs
@@ -0,0 +1,21 @@
+#![feature(rustc_attrs, const_let, const_fn)]
+
+use std::cell::Cell;
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {}
+
+const fn foo() -> NonZero<Cell<u32>> {
+    let mut x = unsafe { NonZero(Cell::new(1)) };
+    let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability
+    //~^ ERROR borrow of layout constrained field with interior mutability
+    unsafe { NonZero(Cell::new(1)) }
+}
+
+const fn bar() -> NonZero<Cell<u32>> {
+    let mut x = unsafe { NonZero(Cell::new(1)) };
+    let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut
+    unsafe { NonZero(Cell::new(1)) }
+}
diff --git a/src/test/ui/unsafe/ranged_ints3_const.stderr b/src/test/ui/unsafe/ranged_ints3_const.stderr
new file mode 100644
index 00000000000..d83d75787d9
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints3_const.stderr
@@ -0,0 +1,24 @@
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/ranged_ints3_const.rs:12:13
+   |
+LL |     let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability
+   |             ^^^^
+
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/ranged_ints3_const.rs:19:22
+   |
+LL |     let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut
+   |                      ^^^^
+
+error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints3_const.rs:12:13
+   |
+LL |     let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability
+   |             ^^^^ borrow of layout constrained field with interior mutability
+   |
+   = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0133, E0492.
+For more information about an error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints4.rs b/src/test/ui/unsafe/ranged_ints4.rs
new file mode 100644
index 00000000000..d8632c48434
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints4.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {
+    let mut x = unsafe { NonZero(1) };
+    x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe
+}
diff --git a/src/test/ui/unsafe/ranged_ints4.stderr b/src/test/ui/unsafe/ranged_ints4.stderr
new file mode 100644
index 00000000000..c6468b643b4
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints4.stderr
@@ -0,0 +1,11 @@
+error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints4.rs:8:5
+   |
+LL |     x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe
+   |     ^^^^^^^ mutation of layout constrained field
+   |
+   = note: mutating layout constrained fields cannot statically be checked for valid values
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints4_const.rs b/src/test/ui/unsafe/ranged_ints4_const.rs
new file mode 100644
index 00000000000..f589e4739ba
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints4_const.rs
@@ -0,0 +1,19 @@
+#![feature(rustc_attrs, const_let, const_fn)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {}
+
+const fn foo() -> NonZero<u32> {
+    let mut x = unsafe { NonZero(1) };
+    x.0 = 0;
+    //~^ ERROR mutation of layout constrained field is unsafe
+    x
+}
+
+const fn bar() -> NonZero<u32> {
+    let mut x = unsafe { NonZero(1) };
+    unsafe { x.0 = 0 }; // this is UB
+    x
+}
diff --git a/src/test/ui/unsafe/ranged_ints4_const.stderr b/src/test/ui/unsafe/ranged_ints4_const.stderr
new file mode 100644
index 00000000000..fe83b15ce5c
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints4_const.stderr
@@ -0,0 +1,11 @@
+error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints4_const.rs:10:5
+   |
+LL |     x.0 = 0;
+   |     ^^^^^^^ mutation of layout constrained field
+   |
+   = note: mutating layout constrained fields cannot statically be checked for valid values
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs
new file mode 100644
index 00000000000..8477772867e
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints_const.rs
@@ -0,0 +1,11 @@
+#![feature(rustc_attrs)]
+
+#[rustc_layout_scalar_valid_range_start(1)]
+#[repr(transparent)]
+pub(crate) struct NonZero<T>(pub(crate) T);
+fn main() {}
+
+const fn foo() -> NonZero<u32> { NonZero(0) }
+//~^ ERROR initializing type with `rustc_layout_scalar_valid_range` attr is unsafe
+
+const fn bar() -> NonZero<u32> { unsafe { NonZero(0) } }
diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.stderr
new file mode 100644
index 00000000000..584ad40a92b
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints_const.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints_const.rs:8:34
+   |
+LL | const fn foo() -> NonZero<u32> { NonZero(0) }
+   |                                  ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.