From f2ae7b78d63695c1b9ff7bdf4079c7a02e77f73e Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 00:22:12 +0100
Subject: [PATCH 01/23] Allow calling `const unsafe fn` in `const fn` behind a
 feature gate

---
 src/librustc/mir/mod.rs                       |  3 +-
 src/librustc/ty/constness.rs                  |  4 +-
 src/librustc_mir/build/mod.rs                 |  9 ++-
 src/librustc_mir/transform/check_unsafety.rs  | 81 +++++++++++++------
 src/libsyntax/feature_gate.rs                 |  3 +
 .../min_const_fn/min_const_fn_unsafe.rs       |  2 +
 .../min_const_fn/min_const_fn_unsafe.stderr   | 14 ++--
 .../min_const_fn_unsafe_feature_gate.rs       | 56 +++++++++++++
 .../min_const_fn_unsafe_feature_gate.stderr   | 59 ++++++++++++++
 9 files changed, 194 insertions(+), 37 deletions(-)
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr

diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 368f83eb61127..c0581121efa1c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2770,7 +2770,8 @@ 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
+    /// Right now function calls to `const unsafe fn` are the only permitted unsafe operation in
+    /// const fn. Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations
     MinConstFn,
     ExternStatic(ast::NodeId),
     BorrowPacked(ast::NodeId),
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index e32913b8905b7..f067a125c5dc9 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             }
             // 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) {
+            self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
                 // stable functions with unstable const fn aren't `min_const_fn`
                 Some(&attr::Stability { const_stability: Some(_), .. }) => false,
                 // unstable functions don't need to conform
@@ -66,7 +66,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             }
         } else {
             // users enabling the `const_fn` feature gate can do what they want
-            !self.features().const_fn
+            self.is_const_fn_raw(def_id) && !self.features().const_fn
         }
     }
 }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index d95a74be77696..cc927df6350bd 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(..) => {
@@ -113,6 +114,12 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
                 hir::Unsafety::Normal => Safety::Safe,
                 hir::Unsafety::Unsafe => Safety::FnUnsafe,
             };
+            let safety = if implicit_argument.is_none() && tcx.is_min_const_fn(fn_def_id) {
+                // the body of `const unsafe fn`s is treated like the body of safe `const fn`s
+                Safety::Safe
+            } else {
+                safety
+            };
 
             let body = tcx.hir.body(body_id);
             let explicit_arguments =
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 3404772f8255f..d096bb32d9586 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -34,6 +34,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 +94,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::MinConstFn)
                 }
             }
         }
@@ -121,7 +122,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);
@@ -189,7 +191,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 +214,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 +240,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 +264,70 @@ 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) {
+            // FIXME: erring on the safe side here and disallowing builtin unsafety in const fn
+            (Safety::BuiltinUnsafe, true) |
+            // `unsafe` blocks are required even in `const unsafe fn`
+            (Safety::FnUnsafe, true) |
+            // `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();
+                    if self.min_const_fn {
+                        // overwrite unsafety violation in const fn with a single hard error kind
+                        violation.kind = UnsafetyViolationKind::MinConstFn;
+                    } else if let UnsafetyViolationKind::MinConstFn = violation.kind {
+                        // outside of const fns we treat `MinConstFn` and `General` the same
+                        violation.kind = UnsafetyViolationKind::General;
+                    }
+                    if !self.violations.contains(&violation) {
+                        self.violations.push(violation)
                     }
                 }
                 false
             }
-            Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
-            Safety::ExplicitUnsafe(node_id) => {
+            (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true,
+            (Safety::ExplicitUnsafe(node_id), _) => {
                 if !violations.is_empty() {
                     self.used_unsafe.insert(node_id);
                 }
+                // only some unsafety is allowed in const fn
+                if self.min_const_fn {
+                    for violation in violations {
+                        match violation.kind {
+                            // these are allowed
+                            UnsafetyViolationKind::MinConstFn
+                                if self.tcx.sess.features_untracked().min_const_unsafe_fn => {},
+                            _ => {
+                                let mut violation = violation.clone();
+                                // overwrite unsafety violation in const fn with a hard error
+                                violation.kind = UnsafetyViolationKind::MinConstFn;
+                                if !self.violations.contains(&violation) {
+                                    self.violations.push(violation)
+                                }
+                            },
+                        }
+                    }
+                }
                 true
             }
         };
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index fac7ff2bf342d..026b159f80f9a 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/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
index 67332c6d2cfb2..7a84992e14b36 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,6 +8,8 @@
 // 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 }
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 8cff0d491d8a4..17cba8569c148 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,5 +1,5 @@
 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:29:51
    |
 LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
    |                                                   ^^
@@ -7,7 +7,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe
    = 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:36:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ 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
+  --> $DIR/min_const_fn_unsafe.rs:21:14
    |
 LL |     unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
    |              ^^^^^^ call to unsafe function
@@ -23,7 +23,7 @@ LL |     unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:22:14
+  --> $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
@@ -31,7 +31,7 @@ LL |     unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:25:14
+  --> $DIR/min_const_fn_unsafe.rs:27:14
    |
 LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
@@ -39,7 +39,7 @@ LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 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:29:51
    |
 LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
    |                                                   ^^ dereference of raw pointer
@@ -47,7 +47,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe
    = 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.rs:34:5
+  --> $DIR/min_const_fn_unsafe.rs:36:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^ access to union field
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 0000000000000..f3e85ebe5f60b
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs
@@ -0,0 +1,56 @@
+// 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
+
+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 0000000000000..78bf99b0a4d99
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr
@@ -0,0 +1,59 @@
+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]: unions in const fn are unstable (see issue #51909)
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:54: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
+
+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
+
+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
+
+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
+
+error: access to union field is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:54: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
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.

From 906a49eef27c927ff73ed5712d5cd663b06d8963 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 11:09:52 +0100
Subject: [PATCH 02/23] Document unsafe rules with comments and `bug!` calls

---
 src/librustc_mir/transform/check_unsafety.rs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index d096bb32d9586..0547e4476cbe4 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -284,10 +284,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                            unsafe_blocks: &[(ast::NodeId, bool)]) {
         let safety = self.source_scope_local_data[self.source_info.scope].safety;
         let within_unsafe = match (safety, self.min_const_fn) {
-            // FIXME: erring on the safe side here and disallowing builtin unsafety in const fn
+            // Erring on the safe side, pun intended
             (Safety::BuiltinUnsafe, true) |
-            // `unsafe` blocks are required even in `const unsafe fn`
-            (Safety::FnUnsafe, 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 {
@@ -305,8 +305,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                 }
                 false
             }
+            // 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);
                 }
@@ -316,6 +318,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                         match violation.kind {
                             // these are allowed
                             UnsafetyViolationKind::MinConstFn
+                                // if `#![feature(min_const_unsafe_fn)]` is active
                                 if self.tcx.sess.features_untracked().min_const_unsafe_fn => {},
                             _ => {
                                 let mut violation = violation.clone();

From cc3470ce3b0ef74eab0f46d865d4d6021911b284 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 12:08:19 +0100
Subject: [PATCH 03/23] Add test for dereferencing raw pointers and immediately
 referencing again

---
 .../min_const_fn_unsafe_feature_gate.rs       |  3 +++
 .../min_const_fn_unsafe_feature_gate.stderr   | 22 ++++++++++++++++---
 2 files changed, 22 insertions(+), 3 deletions(-)

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
index f3e85ebe5f60b..b66460d64089b 100644
--- 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
@@ -47,6 +47,9 @@ const unsafe fn foo10_2() -> *const Vec<std::cell::Cell<u32>> {
 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
+
 fn main() {}
 
 const unsafe fn no_union() {
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
index 78bf99b0a4d99..d88ed1a5ad2cf 100644
--- 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
@@ -6,8 +6,16 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe
    |
    = 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]: unions in const fn are unstable (see issue #51909)
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:57:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^
@@ -46,14 +54,22 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe
    |
    = 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: 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
+
 error: access to union field is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe_feature_gate.rs:54:5
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:57: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
 
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0658`.

From 02b22323f129446c9e2255d0eeab6c7ab17aac52 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 13:03:05 +0100
Subject: [PATCH 04/23] Make sure the initialization of constrained int range
 newtypes is unsafe

---
 src/libcore/lib.rs                            |  1 +
 src/libcore/nonzero.rs                        | 10 +++-
 src/libcore/num/mod.rs                        |  4 +-
 src/libcore/ptr.rs                            | 14 +++---
 src/librustc_mir/transform/check_unsafety.rs  | 16 ++++++-
 .../min_const_unsafe_fn_libstd_stability.rs   | 47 +++++++++++++++++++
 ...in_const_unsafe_fn_libstd_stability.stderr | 26 ++++++++++
 .../min_const_unsafe_fn_libstd_stability2.rs  | 43 +++++++++++++++++
 ...n_const_unsafe_fn_libstd_stability2.stderr | 20 ++++++++
 9 files changed, 169 insertions(+), 12 deletions(-)
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
 create mode 100644 src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 726e891df0ccf..d070160609d29 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -93,6 +93,7 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(exhaustive_patterns)]
+#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
 #![feature(no_core)]
 #![feature(on_unimplemented)]
 #![feature(optin_builtin_traits)]
diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs
index 436cd1fc05728..22d93a5301efa 100644
--- a/src/libcore/nonzero.rs
+++ b/src/libcore/nonzero.rs
@@ -15,10 +15,18 @@ use ops::{CoerceUnsized, DispatchFromDyn};
 /// 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);
 
+// Do not call `T::clone` as theoretically it could turn the field into `0`
+// invalidating `NonZero`'s invariant.
+impl<T: Copy> Clone for NonZero<T> {
+    fn clone(&self) -> Self {
+        unsafe { NonZero(self.0) }
+    }
+}
+
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
 
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 805be431328e2..7f5d596b220b9 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 d3a74ed2a6856..a07c7260f712c 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(NonNull { pointer: unsafe { NonZero(ptr as _) } })
         } 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_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 0547e4476cbe4..2c80e57374999 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -24,6 +24,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
 use syntax::ast;
 use syntax::symbol::Symbol;
 
+use std::ops::Bound;
+
 use util;
 
 pub struct UnsafetyChecker<'a, 'tcx: 'a> {
@@ -136,8 +138,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 `NonZero` with a `0` violates layout constraints \
+                            and is undefined behavior",
+                            UnsafetyViolationKind::MinConstFn,
+                        ),
+                    }
+                }
                 &AggregateKind::Closure(def_id, _) |
                 &AggregateKind::Generator(def_id, _, _) => {
                     let UnsafetyCheckResult {
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 0000000000000..f559c23ff0f54
--- /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 0000000000000..37be2889173f8
--- /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 0000000000000..131bc97c85a2a
--- /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 0000000000000..0b58dc1294be0
--- /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
+

From ec6573f33b15275551af321df1a19cfd3d835982 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 15:08:27 +0100
Subject: [PATCH 05/23] Make `newtype_index` safe

---
 src/librustc/dep_graph/graph.rs               |  1 +
 src/librustc/dep_graph/serialized.rs          |  1 +
 src/librustc/lib.rs                           |  1 +
 src/librustc/middle/region.rs                 |  1 +
 src/librustc/mir/mod.rs                       |  2 +-
 src/librustc/ty/mod.rs                        |  2 +-
 src/librustc/ty/sty.rs                        |  2 +-
 src/librustc_data_structures/indexed_vec.rs   | 24 +++++++++++++++----
 src/librustc_mir/borrow_check/location.rs     |  1 +
 .../borrow_check/nll/constraints/mod.rs       |  1 +
 .../borrow_check/nll/region_infer/values.rs   |  1 +
 .../nll/type_check/liveness/liveness_map.rs   |  1 +
 .../nll/type_check/liveness/local_use_map.rs  |  1 +
 src/librustc_mir/build/mod.rs                 |  1 +
 14 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 4c94c993ab405..06287bda63a49 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -18,6 +18,7 @@ use std::env;
 use std::hash::Hash;
 use ty::{self, TyCtxt};
 use util::common::{ProfileQueriesMsg, profq_msg};
+use serialize::{Decodable, Decoder};
 
 use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
 
diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs
index 0c6c224fa914c..992ebd0efb15f 100644
--- a/src/librustc/dep_graph/serialized.rs
+++ b/src/librustc/dep_graph/serialized.rs
@@ -13,6 +13,7 @@
 use dep_graph::DepNode;
 use ich::Fingerprint;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use serialize::{Decodable, Decoder};
 
 newtype_index! {
     pub struct SerializedDepNodeIndex { .. }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index ddb0c5bf22ab6..99412c02c43a6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -69,6 +69,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
 #![feature(transpose_result)]
+#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
 
 #![recursion_limit="512"]
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 35d1a4dd2cb7c..1440d91b47e63 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -28,6 +28,7 @@ use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 use ty::TyCtxt;
 use ty::query::Providers;
+use serialize::{Decodable, Decoder};
 
 use hir;
 use hir::Node;
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index c0581121efa1c..549e13bad642a 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, Decodable, Decoder};
 use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Formatter, Write};
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4633ab1166347..8ff93cee25022 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -41,7 +41,7 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 use arena::SyncDroplessArena;
 use session::DataTypeKind;
 
-use serialize::{self, Encodable, Encoder};
+use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use std::cell::RefCell;
 use std::cmp::{self, Ordering};
 use std::fmt;
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 1416cb17feaed..fa45b8c776837 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -29,7 +29,7 @@ use rustc_target::spec::abi;
 use syntax::ast::{self, Ident};
 use syntax::symbol::{keywords, InternedString};
 
-use serialize;
+use serialize::{self, Decodable, Decoder};
 
 use hir;
 
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index a59bf9d530c4d..c35490ce35b4f 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,17 @@ 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)*);
+        impl Decodable for $type {
+            fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+                d.read_u32().into()
+            }
+        }
     );
 
     // The case where no derives are added, but encodable is overridden. Don't
@@ -360,12 +371,17 @@ 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)*);
+        impl Decodable for $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/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs
index b3e159dd84457..2d593d851138b 100644
--- a/src/librustc_mir/borrow_check/location.rs
+++ b/src/librustc_mir/borrow_check/location.rs
@@ -10,6 +10,7 @@
 
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_serialize::{Decodable, Decoder};
 
 /// Maps between a MIR Location, which identifies a particular
 /// statement within a basic block, to a "rich location", which
diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
index a873af8333a7f..37b11a77184d4 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
@@ -13,6 +13,7 @@ use rustc::ty::RegionVid;
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use borrow_check::nll::type_check::Locations;
+use rustc_serialize::{Decodable, Decoder};
 
 use std::fmt;
 use std::ops::Deref;
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 69e2c896d33e5..5ce80ca236dbb 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -16,6 +16,7 @@ use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
 use std::rc::Rc;
+use rustc_serialize::{Decodable, Decoder};
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 crate struct RegionValueElements {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
index cc176cbc40392..d1a1d2aea248a 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
@@ -23,6 +23,7 @@ use rustc::ty::{RegionVid, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use util::liveness::LiveVariableMap;
+use rustc_serialize::{Decodable, Decoder};
 
 /// Map between Local and LiveVar indices: the purpose of this
 /// map is to define the subset of local variables for which we need
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
index 4b39d58cd96a8..9e0eaf61e94a4 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
@@ -15,6 +15,7 @@ use rustc::mir::{Local, Location, Mir};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::vec_linked_list as vll;
 use util::liveness::{categorize, DefUse, LiveVariableMap};
+use rustc_serialize::{Decodable, Decoder};
 
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index cc927df6350bd..1a5a089c7aa03 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -32,6 +32,7 @@ use syntax::ast;
 use syntax::attr::{self, UnwindAttr};
 use syntax::symbol::keywords;
 use syntax_pos::Span;
+use rustc_serialize::{Decodable, Decoder};
 use transform::MirSource;
 use util as mir_util;
 

From 693c55372e950bcf19a95d713a82250a5f4d1bba Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 15:21:44 +0100
Subject: [PATCH 06/23] Move ref to packed struct field check into projection
 arm

---
 src/librustc_mir/transform/check_unsafety.rs | 36 ++++++++++----------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 2c80e57374999..1e90f5a9584b2 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -166,28 +166,28 @@ 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 old_source_info = self.source_info;
                 if let &Place::Local(local) = base {
                     if self.mir.local_decls[local].internal {

From 8bdb11c4d94a05c3d6148e52b53a6b95ec9f0a13 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 16:30:05 +0100
Subject: [PATCH 07/23] Forbid the creation of mutable borrows to fields of
 layout constrained types

---
 src/librustc_mir/transform/check_unsafety.rs | 40 ++++++++++++++++++++
 src/test/ui/unsafe/ranged_ints.rs            |  8 ++++
 src/test/ui/unsafe/ranged_ints.stderr        | 11 ++++++
 src/test/ui/unsafe/ranged_ints2.rs           |  9 +++++
 src/test/ui/unsafe/ranged_ints2.stderr       | 11 ++++++
 5 files changed, 79 insertions(+)
 create mode 100644 src/test/ui/unsafe/ranged_ints.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints.stderr
 create mode 100644 src/test/ui/unsafe/ranged_ints2.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints2.stderr

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 1e90f5a9584b2..05052c8a8c8c9 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -187,6 +187,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             kind: UnsafetyViolationKind::BorrowPacked(lint_root)
                         }], &[]);
                     }
+                    if context.is_mutating_use() {
+                        self.check_mut_borrowing_layout_constrained_field(place);
+                    }
                 }
                 let old_source_info = self.source_info;
                 if let &Place::Local(local) = base {
@@ -350,6 +353,43 @@ 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>,
+    ) {
+        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 source_info = self.source_info;
+                                self.register_violations(&[UnsafetyViolation {
+                                    source_info,
+                                    description: Symbol::intern(
+                                        "borrow of layout constrained field",
+                                    ).as_interned_str(),
+                                    details:
+                                        Symbol::intern(
+                                            "references to fields of layout constrained fields \
+                                            lose the constraints",
+                                        ).as_interned_str(),
+                                    kind: UnsafetyViolationKind::MinConstFn,
+                                }], &[]);
+                            }
+                        },
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+            place = base;
+        }
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs
new file mode 100644
index 0000000000000..c9fdadeaf05fd
--- /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
+}
\ No newline at end of file
diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr
new file mode 100644
index 0000000000000..c28adba9ee536
--- /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 `NonZero` with a `0` violates layout constraints and 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 0000000000000..9e1acb1a7b1a3
--- /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 borrow of layout constrained field is unsafe
+}
\ No newline at end of file
diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr
new file mode 100644
index 0000000000000..77313f27a420b
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints2.stderr
@@ -0,0 +1,11 @@
+error[E0133]: borrow 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 borrow of layout constrained field is unsafe
+   |             ^^^^^^^^ borrow of layout constrained field
+   |
+   = note: references to fields of layout constrained fields lose the constraints
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.

From 14218e39698156b3c0c9b64b5cc17ee4c9ed17e0 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 3 Nov 2018 23:39:29 +0100
Subject: [PATCH 08/23] Trailing newlines again

---
 src/test/ui/unsafe/ranged_ints.rs  | 2 +-
 src/test/ui/unsafe/ranged_ints2.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs
index c9fdadeaf05fd..0fa2da917e9f8 100644
--- a/src/test/ui/unsafe/ranged_ints.rs
+++ b/src/test/ui/unsafe/ranged_ints.rs
@@ -5,4 +5,4 @@
 pub(crate) struct NonZero<T>(pub(crate) T);
 fn main() {
     let _x = NonZero(0); //~ ERROR initializing type with `rustc_layout_scalar_valid_range` attr
-}
\ No newline at end of file
+}
diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs
index 9e1acb1a7b1a3..3738b7f5af4a7 100644
--- a/src/test/ui/unsafe/ranged_ints2.rs
+++ b/src/test/ui/unsafe/ranged_ints2.rs
@@ -6,4 +6,4 @@ pub(crate) struct NonZero<T>(pub(crate) T);
 fn main() {
     let mut x = unsafe { NonZero(1) };
     let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe
-}
\ No newline at end of file
+}

From c4a850078cbcc8cd3d79483b51767f1171d81f88 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sun, 4 Nov 2018 12:22:58 +0100
Subject: [PATCH 09/23] Adjust a rustc test to the safety changes

---
 src/test/run-pass-fulldeps/newtype_index.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs
index 3cd622a33b173..4c5a21201d674 100644
--- a/src/test/run-pass-fulldeps/newtype_index.rs
+++ b/src/test/run-pass-fulldeps/newtype_index.rs
@@ -1,7 +1,8 @@
-#![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;
+use rustc_serialize::{Decodable, Decoder};
 
 use rustc_data_structures::indexed_vec::Idx;
 

From 081c49783f5cfc24f66f3ac36244d816567cc120 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sun, 4 Nov 2018 12:48:51 +0100
Subject: [PATCH 10/23] generalize the message about the creation of layout
 restricted types

---
 src/librustc_mir/transform/check_unsafety.rs | 4 ++--
 src/test/ui/unsafe/ranged_ints.stderr        | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 05052c8a8c8c9..2a80f27ecab5a 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -144,8 +144,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                         (Bound::Unbounded, Bound::Unbounded) => {},
                         _ => self.require_unsafe(
                             "initializing type with `rustc_layout_scalar_valid_range` attr",
-                            "initializing `NonZero` with a `0` violates layout constraints \
-                            and is undefined behavior",
+                            "initializing a layout restricted type's field with a value outside \
+                            the valid range is undefined behavior",
                             UnsafetyViolationKind::MinConstFn,
                         ),
                     }
diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.stderr
index c28adba9ee536..f59a930b5a901 100644
--- a/src/test/ui/unsafe/ranged_ints.stderr
+++ b/src/test/ui/unsafe/ranged_ints.stderr
@@ -4,7 +4,7 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is u
 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 `NonZero` with a `0` violates layout constraints and is undefined behavior
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
 
 error: aborting due to previous error
 

From 1894a5fe2c72a1e22897026f34e5f9035cc169ff Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sun, 4 Nov 2018 13:45:26 +0100
Subject: [PATCH 11/23] Also make immutable references to non-freeze restricted
 value range types unsafe

---
 src/libcore/marker.rs                        |  2 +-
 src/libcore/nonzero.rs                       |  9 +++++----
 src/librustc_mir/transform/check_unsafety.rs |  6 +++++-
 src/test/ui/unsafe/ranged_ints3.rs           | 11 +++++++++++
 src/test/ui/unsafe/ranged_ints3.stderr       | 11 +++++++++++
 5 files changed, 33 insertions(+), 6 deletions(-)
 create mode 100644 src/test/ui/unsafe/ranged_ints3.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints3.stderr

diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 3bcdfabbb245e..23f07773f3f34 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 22d93a5301efa..a89c6ca60cbea 100644
--- a/src/libcore/nonzero.rs
+++ b/src/libcore/nonzero.rs
@@ -11,22 +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, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[repr(transparent)]
-pub(crate) struct NonZero<T>(pub(crate) T);
+pub(crate) struct NonZero<T: Freeze>(pub(crate) T);
 
 // Do not call `T::clone` as theoretically it could turn the field into `0`
 // invalidating `NonZero`'s invariant.
-impl<T: Copy> Clone for NonZero<T> {
+impl<T: Copy + Freeze> Clone for NonZero<T> {
     fn clone(&self) -> Self {
         unsafe { NonZero(self.0) }
     }
 }
 
-impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
+impl<T: CoerceUnsized<U> + Freeze, U: Freeze> CoerceUnsized<NonZero<U>> for NonZero<T> {}
 
-impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
+impl<T: DispatchFromDyn<U> + Freeze, U: Freeze> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 2a80f27ecab5a..c7a785ad2c520 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -187,7 +187,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             kind: UnsafetyViolationKind::BorrowPacked(lint_root)
                         }], &[]);
                     }
-                    if context.is_mutating_use() {
+                    let is_freeze = base
+                        .ty(self.mir, self.tcx)
+                        .to_ty(self.tcx)
+                        .is_freeze(self.tcx, self.param_env, self.source_info.span);
+                    if context.is_mutating_use() || !is_freeze {
                         self.check_mut_borrowing_layout_constrained_field(place);
                     }
                 }
diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs
new file mode 100644
index 0000000000000..d68c712227af2
--- /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 is unsafe
+}
diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr
new file mode 100644
index 0000000000000..b5aa9089b5f62
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints3.stderr
@@ -0,0 +1,11 @@
+error[E0133]: borrow of layout constrained field 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 is unsafe
+   |             ^^^^ borrow of layout constrained field
+   |
+   = note: references to fields of layout constrained fields lose the constraints
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.

From 55abc0bc907b84b0fe7a9a4793c1549dad978762 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 5 Nov 2018 13:26:07 +0100
Subject: [PATCH 12/23] Also prevent mutation fields directly

---
 src/librustc_mir/transform/check_unsafety.rs | 42 +++++++++++++-------
 src/test/ui/unsafe/ranged_ints2.rs           |  2 +-
 src/test/ui/unsafe/ranged_ints2.stderr       |  8 ++--
 src/test/ui/unsafe/ranged_ints3.rs           |  2 +-
 src/test/ui/unsafe/ranged_ints3.stderr       |  8 ++--
 src/test/ui/unsafe/ranged_ints4.rs           |  9 +++++
 src/test/ui/unsafe/ranged_ints4.stderr       | 11 +++++
 7 files changed, 57 insertions(+), 25 deletions(-)
 create mode 100644 src/test/ui/unsafe/ranged_ints4.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints4.stderr

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index c7a785ad2c520..b124f8b1c0be9 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -187,13 +187,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             kind: UnsafetyViolationKind::BorrowPacked(lint_root)
                         }], &[]);
                     }
-                    let is_freeze = base
-                        .ty(self.mir, self.tcx)
-                        .to_ty(self.tcx)
-                        .is_freeze(self.tcx, self.param_env, self.source_info.span);
-                    if context.is_mutating_use() || !is_freeze {
-                        self.check_mut_borrowing_layout_constrained_field(place);
-                    }
+                }
+                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);
+                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 {
@@ -360,6 +362,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
     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
@@ -371,17 +374,26 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                         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(
-                                        "borrow of layout constrained field",
-                                    ).as_interned_str(),
-                                    details:
-                                        Symbol::intern(
-                                            "references to fields of layout constrained fields \
-                                            lose the constraints",
-                                        ).as_interned_str(),
+                                    description: Symbol::intern(description).as_interned_str(),
+                                    details: Symbol::intern(details).as_interned_str(),
                                     kind: UnsafetyViolationKind::MinConstFn,
                                 }], &[]);
                             }
diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs
index 3738b7f5af4a7..68ba120b279c0 100644
--- a/src/test/ui/unsafe/ranged_ints2.rs
+++ b/src/test/ui/unsafe/ranged_ints2.rs
@@ -5,5 +5,5 @@
 pub(crate) struct NonZero<T>(pub(crate) T);
 fn main() {
     let mut x = unsafe { NonZero(1) };
-    let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe
+    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
index 77313f27a420b..ae63f47ed74a7 100644
--- a/src/test/ui/unsafe/ranged_ints2.stderr
+++ b/src/test/ui/unsafe/ranged_ints2.stderr
@@ -1,10 +1,10 @@
-error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block
+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 borrow of layout constrained field is unsafe
-   |             ^^^^^^^^ borrow of layout constrained field
+LL |     let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe
+   |             ^^^^^^^^ mutation of layout constrained field
    |
-   = note: references to fields of layout constrained fields lose the constraints
+   = note: mutating layout constrained fields cannot statically be checked for valid values
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs
index d68c712227af2..47d67fac6785c 100644
--- a/src/test/ui/unsafe/ranged_ints3.rs
+++ b/src/test/ui/unsafe/ranged_ints3.rs
@@ -7,5 +7,5 @@ use std::cell::Cell;
 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 is unsafe
+    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
index b5aa9089b5f62..311a058fdb07f 100644
--- a/src/test/ui/unsafe/ranged_ints3.stderr
+++ b/src/test/ui/unsafe/ranged_ints3.stderr
@@ -1,10 +1,10 @@
-error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block
+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 is unsafe
-   |             ^^^^ borrow of layout constrained field
+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
+   = 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
 
diff --git a/src/test/ui/unsafe/ranged_ints4.rs b/src/test/ui/unsafe/ranged_ints4.rs
new file mode 100644
index 0000000000000..d8632c48434f2
--- /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 0000000000000..c6468b643b41a
--- /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`.

From e5d90652e203aee41ae41b7ad696652e77654766 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 5 Nov 2018 13:29:17 +0100
Subject: [PATCH 13/23] Comment on the unsafety code for layout constrained
 fields

---
 src/librustc_mir/transform/check_unsafety.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index b124f8b1c0be9..671ca355dbfc1 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -192,6 +192,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     .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(),

From 4497ff37627d860690613249a31cf3ee4c4195ef Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 5 Nov 2018 18:06:26 +0100
Subject: [PATCH 14/23] Emit feature gate suggestion

---
 src/librustc/ich/impls_mir.rs                 |  3 +-
 src/librustc/mir/mod.rs                       |  8 +-
 src/librustc_mir/transform/check_unsafety.rs  | 74 +++++++++++++------
 .../min_const_fn/min_const_fn_unsafe.rs       |  6 +-
 .../min_const_fn/min_const_fn_unsafe.stderr   | 24 +++---
 5 files changed, 75 insertions(+), 40 deletions(-)

diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index d98bb82aabad1..3b9c8ae2d3c50 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 549e13bad642a..09b344cd38d25 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2770,9 +2770,11 @@ impl Location {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum UnsafetyViolationKind {
     General,
-    /// Right now function calls to `const unsafe fn` are the only permitted unsafe operation in
-    /// const fn. Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations
-    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_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 671ca355dbfc1..25dbd160d19f4 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -23,6 +23,7 @@ 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;
 
@@ -96,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", UnsafetyViolationKind::MinConstFn)
+                         undefined behavior", UnsafetyViolationKind::GatedConstFnCall)
                 }
             }
         }
@@ -146,7 +147,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             "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::MinConstFn,
+                            UnsafetyViolationKind::GeneralAndConstFn,
                         ),
                     }
                 }
@@ -319,12 +320,21 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
             (Safety::Safe, _) => {
                 for violation in violations {
                     let mut violation = violation.clone();
-                    if self.min_const_fn {
-                        // overwrite unsafety violation in const fn with a single hard error kind
-                        violation.kind = UnsafetyViolationKind::MinConstFn;
-                    } else if let UnsafetyViolationKind::MinConstFn = violation.kind {
-                        // outside of const fns we treat `MinConstFn` and `General` the same
-                        violation.kind = UnsafetyViolationKind::General;
+                    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)
@@ -344,13 +354,24 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                     for violation in violations {
                         match violation.kind {
                             // these are allowed
-                            UnsafetyViolationKind::MinConstFn
+                            UnsafetyViolationKind::GatedConstFnCall => {
                                 // if `#![feature(min_const_unsafe_fn)]` is active
-                                if self.tcx.sess.features_untracked().min_const_unsafe_fn => {},
-                            _ => {
+                                if !self.tcx.sess.features_untracked().min_const_unsafe_fn {
+                                    if !self.violations.contains(&violation) {
+                                        self.violations.push(violation.clone())
+                                    }
+                                }
+                            }
+                            // these unsafe things are stable in const fn
+                            UnsafetyViolationKind::GeneralAndConstFn => {},
+                            UnsafetyViolationKind::General |
+                            UnsafetyViolationKind::BorrowPacked(_) |
+                            UnsafetyViolationKind::ExternStatic(_) => {
                                 let mut violation = violation.clone();
-                                // overwrite unsafety violation in const fn with a hard error
-                                violation.kind = UnsafetyViolationKind::MinConstFn;
+                                // 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)
                                 }
@@ -400,7 +421,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                     source_info,
                                     description: Symbol::intern(description).as_interned_str(),
                                     details: Symbol::intern(details).as_interned_str(),
-                                    kind: UnsafetyViolationKind::MinConstFn,
+                                    kind: UnsafetyViolationKind::GeneralAndConstFn,
                                 }], &[]);
                             }
                         },
@@ -592,6 +613,16 @@ 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) => {
+                tcx.sess.struct_span_err(
+                    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();
+            }
+            UnsafetyViolationKind::GeneralAndConstFn |
             UnsafetyViolationKind::General => {
                 struct_span_err!(
                     tcx.sess, source_info.span, E0133,
@@ -600,14 +631,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/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 7a84992e14b36..02a357551df30 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
@@ -18,13 +18,13 @@ const fn no_unsafe() { unsafe {} }
 
 // not ok
 const fn foo8() -> i32 {
-    unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+    unsafe { foo4() } //~ 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
+    unsafe { foo5::<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
+    unsafe { foo6::<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
 //~^ dereferencing raw pointers in constant functions
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 17cba8569c148..0b8ff4717c128 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
@@ -14,29 +14,29 @@ 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
+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 { foo4() } //~ 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
+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 { foo5::<String>() } //~ 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
+error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607)
   --> $DIR/min_const_fn_unsafe.rs:27:14
    |
-LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR calls to `const unsafe fn` in const fns
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = 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:29:51

From 37ef5e43af477d0cb04f70e9d868361b40cd7a08 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 6 Nov 2018 17:43:32 +0100
Subject: [PATCH 15/23] Add tests for stable unsafe features in const fn

---
 src/libcore/lib.rs                           |  1 -
 src/librustc/hir/mod.rs                      |  1 +
 src/librustc/lib.rs                          |  1 -
 src/librustc_target/abi/mod.rs               |  1 +
 src/test/ui/unsafe/ranged_ints2_const.rs     | 20 ++++++++++++++
 src/test/ui/unsafe/ranged_ints2_const.stderr | 24 +++++++++++++++++
 src/test/ui/unsafe/ranged_ints3_const.rs     | 21 +++++++++++++++
 src/test/ui/unsafe/ranged_ints3_const.stderr | 24 +++++++++++++++++
 src/test/ui/unsafe/ranged_ints4_const.rs     | 19 +++++++++++++
 src/test/ui/unsafe/ranged_ints4_const.stderr | 28 ++++++++++++++++++++
 src/test/ui/unsafe/ranged_ints_const.rs      | 11 ++++++++
 src/test/ui/unsafe/ranged_ints_const.stderr  | 11 ++++++++
 12 files changed, 160 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/unsafe/ranged_ints2_const.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints2_const.stderr
 create mode 100644 src/test/ui/unsafe/ranged_ints3_const.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints3_const.stderr
 create mode 100644 src/test/ui/unsafe/ranged_ints4_const.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints4_const.stderr
 create mode 100644 src/test/ui/unsafe/ranged_ints_const.rs
 create mode 100644 src/test/ui/unsafe/ranged_ints_const.stderr

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index d070160609d29..726e891df0ccf 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -93,7 +93,6 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(exhaustive_patterns)]
-#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
 #![feature(no_core)]
 #![feature(on_unimplemented)]
 #![feature(optin_builtin_traits)]
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1674320165e65..597a773821703 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -122,6 +122,7 @@ impl serialize::UseSpecializedDecodable for HirId {
 // hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
 mod item_local_id_inner {
     use rustc_data_structures::indexed_vec::Idx;
+    use serialize::{Decodable, Decoder};
     /// An `ItemLocalId` uniquely identifies something within a given "item-like",
     /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
     /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 99412c02c43a6..ddb0c5bf22ab6 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -69,7 +69,6 @@
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
 #![feature(transpose_result)]
-#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
 
 #![recursion_limit="512"]
 
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 50ce0ad6915da..27a4292543ad6 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -17,6 +17,7 @@ use std::fmt;
 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
 
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_serialize::{Decodable, Decoder};
 
 pub mod call;
 
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 0000000000000..a61e3329bdce8
--- /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 0000000000000..f79792ffba9be
--- /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_const.rs b/src/test/ui/unsafe/ranged_ints3_const.rs
new file mode 100644
index 0000000000000..6497b611224b6
--- /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 0000000000000..d83d75787d948
--- /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_const.rs b/src/test/ui/unsafe/ranged_ints4_const.rs
new file mode 100644
index 0000000000000..09689579639e7
--- /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 statements in constant functions are unstable
+    //~^ ERROR mutation of layout constrained field is unsafe
+    x
+}
+
+const fn bar() -> NonZero<u32> {
+    let mut x = unsafe { NonZero(1) };
+    unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable
+    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 0000000000000..284ba3603af2e
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints4_const.stderr
@@ -0,0 +1,28 @@
+error[E0658]: statements in constant functions are unstable (see issue #48821)
+  --> $DIR/ranged_ints4_const.rs:10:5
+   |
+LL |     x.0 = 0; //~ ERROR statements in constant functions are unstable
+   |     ^^^^^^^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
+
+error[E0658]: statements in constant functions are unstable (see issue #48821)
+  --> $DIR/ranged_ints4_const.rs:17:14
+   |
+LL |     unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable
+   |              ^^^^^^^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
+
+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; //~ ERROR statements in constant functions are unstable
+   |     ^^^^^^^ 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: E0133, E0658.
+For more information about an 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 0000000000000..8477772867e91
--- /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 0000000000000..584ad40a92bb0
--- /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`.

From 3ce211dbd0f55f79212fcde773a2060ccfec031d Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 19 Nov 2018 14:45:40 +0100
Subject: [PATCH 16/23] Increase code-reuse and -readability

---
 src/libcore/ptr.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index a07c7260f712c..0387708033b53 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -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: unsafe { NonZero(ptr as _) } })
+            Some(unsafe { Self::new_unchecked(ptr) })
         } else {
             None
         }

From 137a640d61a4c0fe3c88ae0062d1ae01faf8fbf5 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 19 Nov 2018 15:24:03 +0100
Subject: [PATCH 17/23] Automatically generate imports for newtype_index
 `Deserialize` impls

---
 src/librustc/dep_graph/graph.rs               |  1 -
 src/librustc/dep_graph/serialized.rs          |  1 -
 src/librustc/hir/mod.rs                       |  1 -
 src/librustc/middle/region.rs                 |  1 -
 src/librustc/mir/mod.rs                       |  2 +-
 src/librustc/ty/mod.rs                        |  2 +-
 src/librustc/ty/sty.rs                        |  2 +-
 src/librustc_data_structures/indexed_vec.rs   | 24 ++++++++++++-------
 src/librustc_mir/borrow_check/location.rs     |  1 -
 .../borrow_check/nll/constraints/mod.rs       |  1 -
 .../borrow_check/nll/region_infer/values.rs   |  1 -
 .../nll/type_check/liveness/liveness_map.rs   |  1 -
 .../nll/type_check/liveness/local_use_map.rs  |  1 -
 src/librustc_mir/build/mod.rs                 |  1 -
 src/librustc_target/abi/mod.rs                |  1 -
 15 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 06287bda63a49..4c94c993ab405 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -18,7 +18,6 @@ use std::env;
 use std::hash::Hash;
 use ty::{self, TyCtxt};
 use util::common::{ProfileQueriesMsg, profq_msg};
-use serialize::{Decodable, Decoder};
 
 use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
 
diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs
index 992ebd0efb15f..0c6c224fa914c 100644
--- a/src/librustc/dep_graph/serialized.rs
+++ b/src/librustc/dep_graph/serialized.rs
@@ -13,7 +13,6 @@
 use dep_graph::DepNode;
 use ich::Fingerprint;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
-use serialize::{Decodable, Decoder};
 
 newtype_index! {
     pub struct SerializedDepNodeIndex { .. }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 597a773821703..1674320165e65 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -122,7 +122,6 @@ impl serialize::UseSpecializedDecodable for HirId {
 // hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
 mod item_local_id_inner {
     use rustc_data_structures::indexed_vec::Idx;
-    use serialize::{Decodable, Decoder};
     /// An `ItemLocalId` uniquely identifies something within a given "item-like",
     /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
     /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 1440d91b47e63..35d1a4dd2cb7c 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -28,7 +28,6 @@ use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 use ty::TyCtxt;
 use ty::query::Providers;
-use serialize::{Decodable, Decoder};
 
 use hir;
 use hir::Node;
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 09b344cd38d25..4a463c0d5a394 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::{self as serialize, Decodable, Decoder};
+use rustc_serialize::{self as serialize};
 use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Formatter, Write};
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 8ff93cee25022..4633ab1166347 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -41,7 +41,7 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 use arena::SyncDroplessArena;
 use session::DataTypeKind;
 
-use serialize::{self, Encodable, Encoder, Decodable, Decoder};
+use serialize::{self, Encodable, Encoder};
 use std::cell::RefCell;
 use std::cmp::{self, Ordering};
 use std::fmt;
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index fa45b8c776837..1416cb17feaed 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -29,7 +29,7 @@ use rustc_target::spec::abi;
 use syntax::ast::{self, Ident};
 use syntax::symbol::{keywords, InternedString};
 
-use serialize::{self, Decodable, Decoder};
+use serialize;
 
 use hir;
 
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index c35490ce35b4f..6522dbe117994 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -340,11 +340,7 @@ macro_rules! newtype_index {
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
-        impl Decodable for $type {
-            fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
-                d.read_u32().into()
-            }
-        }
+        newtype_index!(@decodable $type);
     );
 
     // The case where no derives are added, but encodable is overridden. Don't
@@ -377,9 +373,21 @@ macro_rules! newtype_index {
             @vis          [$v]
             @debug_format [$debug_format]
                           $($tokens)*);
-        impl Decodable for $type {
-            fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
-                d.read_u32().map(Self::from)
+        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)
+                        }
+                    }
+                }
             }
         }
     );
diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs
index 2d593d851138b..b3e159dd84457 100644
--- a/src/librustc_mir/borrow_check/location.rs
+++ b/src/librustc_mir/borrow_check/location.rs
@@ -10,7 +10,6 @@
 
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc_serialize::{Decodable, Decoder};
 
 /// Maps between a MIR Location, which identifies a particular
 /// statement within a basic block, to a "rich location", which
diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
index 37b11a77184d4..a873af8333a7f 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
@@ -13,7 +13,6 @@ use rustc::ty::RegionVid;
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use borrow_check::nll::type_check::Locations;
-use rustc_serialize::{Decodable, Decoder};
 
 use std::fmt;
 use std::ops::Deref;
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 5ce80ca236dbb..69e2c896d33e5 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -16,7 +16,6 @@ use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
 use std::rc::Rc;
-use rustc_serialize::{Decodable, Decoder};
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 crate struct RegionValueElements {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
index d1a1d2aea248a..cc176cbc40392 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
@@ -23,7 +23,6 @@ use rustc::ty::{RegionVid, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use util::liveness::LiveVariableMap;
-use rustc_serialize::{Decodable, Decoder};
 
 /// Map between Local and LiveVar indices: the purpose of this
 /// map is to define the subset of local variables for which we need
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
index 9e0eaf61e94a4..4b39d58cd96a8 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
@@ -15,7 +15,6 @@ use rustc::mir::{Local, Location, Mir};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::vec_linked_list as vll;
 use util::liveness::{categorize, DefUse, LiveVariableMap};
-use rustc_serialize::{Decodable, Decoder};
 
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 1a5a089c7aa03..cc927df6350bd 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -32,7 +32,6 @@ use syntax::ast;
 use syntax::attr::{self, UnwindAttr};
 use syntax::symbol::keywords;
 use syntax_pos::Span;
-use rustc_serialize::{Decodable, Decoder};
 use transform::MirSource;
 use util as mir_util;
 
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 27a4292543ad6..50ce0ad6915da 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -17,7 +17,6 @@ use std::fmt;
 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
 
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc_serialize::{Decodable, Decoder};
 
 pub mod call;
 

From ae0b00cadace32fd85c6786df24a20d6b55a87d2 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 19 Nov 2018 15:24:23 +0100
Subject: [PATCH 18/23] Add and update tests

---
 src/test/run-pass-fulldeps/newtype_index.rs   |  1 -
 .../ui/consts/min_const_fn/min_const_fn.rs    |  6 ++--
 .../min_const_fn/min_const_fn_unsafe.rs       | 22 +++++++-------
 .../min_const_fn/min_const_fn_unsafe.stderr   | 30 +++++++++----------
 .../min_const_fn_unsafe_feature_gate.rs       |  3 ++
 .../min_const_fn_unsafe_feature_gate.stderr   | 22 ++++++++++++--
 src/test/ui/unsafe/ranged_ints4_const.rs      |  4 +--
 src/test/ui/unsafe/ranged_ints4_const.stderr  | 23 ++------------
 8 files changed, 57 insertions(+), 54 deletions(-)

diff --git a/src/test/run-pass-fulldeps/newtype_index.rs b/src/test/run-pass-fulldeps/newtype_index.rs
index 4c5a21201d674..0fd7ccd55fb2d 100644
--- a/src/test/run-pass-fulldeps/newtype_index.rs
+++ b/src/test/run-pass-fulldeps/newtype_index.rs
@@ -2,7 +2,6 @@
 
 #[macro_use] extern crate rustc_data_structures;
 extern crate rustc_serialize;
-use rustc_serialize::{Decodable, Decoder};
 
 use rustc_data_structures::indexed_vec::Idx;
 
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 0dba3a7de5378..43ca9e7539309 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 02a357551df30..f11b43dcd865c 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
@@ -11,22 +11,24 @@
 // 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 calls to `const unsafe fn` in const fns are unstable
+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 calls to `const unsafe fn` in const fns are unstable
+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 calls to `const unsafe fn` in const fns
+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 0b8ff4717c128..8d885545cde56 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,13 +1,13 @@
 error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
-  --> $DIR/min_const_fn_unsafe.rs:29: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:36:5
+  --> $DIR/min_const_fn_unsafe.rs:38:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^
@@ -17,37 +17,37 @@ LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
 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 calls to `const unsafe fn` in const fns are unstable
-   |              ^^^^^^
+LL |     unsafe { ret_i32_no_unsafe() } //~ ERROR calls to `const unsafe fn` in const fns are unstable
+   |              ^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
 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 calls to `const unsafe fn` in const fns are unstable
-   |              ^^^^^^^^^^^^^^^^
+LL |     unsafe { ret_null_ptr_no_unsafe::<String>() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable
 
 error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607)
-  --> $DIR/min_const_fn_unsafe.rs:27:14
+  --> $DIR/min_const_fn_unsafe.rs:28:14
    |
-LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR calls to `const unsafe fn` in const fns
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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:29: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
 
 error: access to union field is unsafe and unsafe operations are not allowed in const fn
-  --> $DIR/min_const_fn_unsafe.rs:36:5
+  --> $DIR/min_const_fn_unsafe.rs:38:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^ access to union field
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
index b66460d64089b..8a6884bc6b93c 100644
--- 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
@@ -50,6 +50,9 @@ const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in
 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() {
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
index d88ed1a5ad2cf..4336db65813b3 100644
--- 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
@@ -14,8 +14,16 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR
    |
    = 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:57:5
+  --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5
    |
 LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
    |     ^^^^^^^^^^^^^^^
@@ -62,14 +70,22 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR
    |
    = 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: 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:57:5
+  --> $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
 
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unsafe/ranged_ints4_const.rs b/src/test/ui/unsafe/ranged_ints4_const.rs
index 09689579639e7..f589e4739baf1 100644
--- a/src/test/ui/unsafe/ranged_ints4_const.rs
+++ b/src/test/ui/unsafe/ranged_ints4_const.rs
@@ -7,13 +7,13 @@ fn main() {}
 
 const fn foo() -> NonZero<u32> {
     let mut x = unsafe { NonZero(1) };
-    x.0 = 0; //~ ERROR statements in constant functions are unstable
+    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 }; //~ ERROR statements in constant functions are unstable
+    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
index 284ba3603af2e..fe83b15ce5cec 100644
--- a/src/test/ui/unsafe/ranged_ints4_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints4_const.stderr
@@ -1,28 +1,11 @@
-error[E0658]: statements in constant functions are unstable (see issue #48821)
-  --> $DIR/ranged_ints4_const.rs:10:5
-   |
-LL |     x.0 = 0; //~ ERROR statements in constant functions are unstable
-   |     ^^^^^^^
-   |
-   = help: add #![feature(const_let)] to the crate attributes to enable
-
-error[E0658]: statements in constant functions are unstable (see issue #48821)
-  --> $DIR/ranged_ints4_const.rs:17:14
-   |
-LL |     unsafe { x.0 = 0 }; //~ ERROR statements in constant functions are unstable
-   |              ^^^^^^^
-   |
-   = help: add #![feature(const_let)] to the crate attributes to enable
-
 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; //~ ERROR statements in constant functions are unstable
+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 3 previous errors
+error: aborting due to previous error
 
-Some errors occurred: E0133, E0658.
-For more information about an error, try `rustc --explain E0133`.
+For more information about this error, try `rustc --explain E0133`.

From b75d5f18677fadef03cc55887a18c804af527d9f Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 30 Nov 2018 18:07:51 +0100
Subject: [PATCH 19/23] Clean up the logic in `is_min_const_fn`

---
 src/librustc/ty/constness.rs | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index f067a125c5dc9..d86170b24f239 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -40,19 +40,24 @@ 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 {
-        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,
-                    _ => {},
-                }
+        // 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() {
+            match &self.item_name(def_id).as_str()[..] {
+                | "size_of"
+                | "min_align_of"
+                | "needs_drop"
+                => return true,
+                _ => {},
             }
+        }
+
+        // Bail out if the signature doesn't contain `const`
+        if !self.is_const_fn_raw(def_id) {
+            return false;
+        }
+
+        if self.features().staged_api {
             // in order for a libstd function to be considered min_const_fn
             // it needs to be stable and have no `rustc_const_unstable` attribute
             self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
@@ -66,7 +71,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             }
         } else {
             // users enabling the `const_fn` feature gate can do what they want
-            self.is_const_fn_raw(def_id) && !self.features().const_fn
+            !self.features().const_fn
         }
     }
 }

From 932dbe816e98d874ca1d7a7f0913ca9f67a94a84 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 30 Nov 2018 18:17:50 +0100
Subject: [PATCH 20/23] Explain unsafety trickery of const functions

---
 src/librustc_mir/build/mod.rs | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index cc927df6350bd..054fb5f458117 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -114,11 +114,20 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
                 hir::Unsafety::Normal => Safety::Safe,
                 hir::Unsafety::Unsafe => Safety::FnUnsafe,
             };
-            let safety = if implicit_argument.is_none() && tcx.is_min_const_fn(fn_def_id) {
-                // the body of `const unsafe fn`s is treated like the body of safe `const fn`s
-                Safety::Safe
-            } else {
-                safety
+
+            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
+                    } else {
+                        Safety::Unsafe
+                    }
+                }
             };
 
             let body = tcx.hir.body(body_id);

From b77969466c23a51fdd7da25aa3ccc98e52d58d3b Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 30 Nov 2018 18:18:42 +0100
Subject: [PATCH 21/23] Clear up some code

---
 src/librustc_mir/build/mod.rs                | 23 ++++++--------------
 src/librustc_mir/transform/check_unsafety.rs | 15 ++++++++-----
 2 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 054fb5f458117..1538c070f373a 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -109,27 +109,18 @@ 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,
             };
 
-            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
-                    } else {
-                        Safety::Unsafe
-                    }
-                }
-            };
-
             let body = tcx.hir.body(body_id);
             let explicit_arguments =
                 body.arguments
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 25dbd160d19f4..b47f1957ab4c9 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -351,19 +351,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                 }
                 // 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 {
-                            // these are allowed
-                            UnsafetyViolationKind::GatedConstFnCall => {
+                            UnsafetyViolationKind::GatedConstFnCall if min_const_unsafe_fn => {
+                                // these function calls to unsafe functions are allowed
                                 // if `#![feature(min_const_unsafe_fn)]` is active
-                                if !self.tcx.sess.features_untracked().min_const_unsafe_fn {
-                                    if !self.violations.contains(&violation) {
-                                        self.violations.push(violation.clone())
-                                    }
+                            },
+                            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(_) => {

From f4115765c5ad16789e9ccdd49dca1a56d47f2b3f Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 1 Dec 2018 14:09:30 +0100
Subject: [PATCH 22/23] Intrinsic checks are just needed for
 `qualify_min_const_fn`

---
 src/librustc/ty/constness.rs                  | 15 +------
 src/librustc_mir/build/mod.rs                 |  2 +-
 src/librustc_mir/transform/check_unsafety.rs  | 18 ++++++---
 .../transform/qualify_min_const_fn.rs         | 40 ++++++++++++++-----
 .../min_const_fn/min_const_fn_unsafe.stderr   |  2 +
 .../min_const_fn_unsafe_feature_gate.stderr   |  6 +++
 6 files changed, 53 insertions(+), 30 deletions(-)

diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index d86170b24f239..bc06167399533 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,18 +39,6 @@ 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 {
-        // 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() {
-            match &self.item_name(def_id).as_str()[..] {
-                | "size_of"
-                | "min_align_of"
-                | "needs_drop"
-                => return true,
-                _ => {},
-            }
-        }
-
         // Bail out if the signature doesn't contain `const`
         if !self.is_const_fn_raw(def_id) {
             return false;
@@ -60,7 +47,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         if self.features().staged_api {
             // in order for a libstd function to be considered min_const_fn
             // it needs to be stable and have no `rustc_const_unstable` attribute
-            self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
+            match self.lookup_stability(def_id) {
                 // stable functions with unstable const fn aren't `min_const_fn`
                 Some(&attr::Stability { const_stability: Some(_), .. }) => false,
                 // unstable functions don't need to conform
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 1538c070f373a..90a204ce00d53 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -115,7 +115,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
                     // 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());
+                    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 b47f1957ab4c9..75f8045cfae99 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -514,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);
 
@@ -617,13 +617,19 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
         // Report an error.
         match kind {
             UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => {
-                tcx.sess.struct_span_err(
+                let mut err = tcx.sess.struct_span_err(
                     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();
+                            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 => {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 13e134ba85928..3c1b9dbd91fa8 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/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 8d885545cde56..922a7883b9f2d 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
@@ -45,6 +45,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no
    |                                                           ^^ 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:38:5
@@ -53,6 +54,7 @@ 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.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr
index 4336db65813b3..20c75afbe638b 100644
--- 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
@@ -37,6 +37,7 @@ 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
@@ -45,6 +46,7 @@ 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
@@ -53,6 +55,7 @@ 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
@@ -61,6 +64,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe
    |                                                   ^^ 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
@@ -69,6 +73,7 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR
    |                                                            ^^^ 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
@@ -85,6 +90,7 @@ 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
 

From cb71752f911c47426e208a9f5f1862d4c0e56aa4 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 4 Dec 2018 11:04:54 +0100
Subject: [PATCH 23/23] Tidy fixup

---
 src/libsyntax/feature_gate.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 026b159f80f9a..bfdc75378d5e1 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -492,7 +492,7 @@ 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),
 );