about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorOliver Schneider <github35764891676564198441@oli-obk.de>2018-08-13 13:48:47 +0200
committerOliver Schneider <github35764891676564198441@oli-obk.de>2018-08-22 18:28:57 +0200
commitbb78426ca8f12f467e4d3bb38e82c0d3b6209e61 (patch)
tree80627d1053b6bb1cdcaea8f50789786613026f04 /src
parent674ef668f13c52a1fadbf01b24d8da1e12d15e70 (diff)
downloadrust-bb78426ca8f12f467e4d3bb38e82c0d3b6209e61.tar.gz
rust-bb78426ca8f12f467e4d3bb38e82c0d3b6209e61.zip
Allow panicking with string literal messages inside constants
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs7
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/mir/interpret/error.rs12
-rw-r--r--src/librustc/ty/structural_impls.rs6
-rw-r--r--src/librustc_mir/interpret/const_eval.rs95
-rw-r--r--src/librustc_mir/interpret/operand.rs2
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs26
-rw-r--r--src/libstd/panicking.rs1
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/ui/const-eval/const_panic.rs22
-rw-r--r--src/test/ui/const-eval/const_panic.stderr33
-rw-r--r--src/test/ui/const-eval/const_panic_libcore.rs22
-rw-r--r--src/test/ui/const-eval/const_panic_libcore.stderr33
-rw-r--r--src/test/ui/const-eval/const_panic_libcore_main.rs35
-rw-r--r--src/test/ui/const-eval/const_panic_libcore_main.stderr33
-rw-r--r--src/test/ui/const-eval/feature-gate-const_panic.rs20
-rw-r--r--src/test/ui/const-eval/feature-gate-const_panic.stderr30
-rw-r--r--src/test/ui/issues/issue-32829.rs2
-rw-r--r--src/test/ui/issues/issue-32829.stderr5
20 files changed, 366 insertions, 25 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 46f4ed4ec47..54829058f44 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -536,7 +536,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
             DeallocateNonBasePtr |
             HeapAllocZeroBytes |
             Unreachable |
-            Panic |
             ReadFromReturnPointer |
             UnimplementedTraitSelection |
             TypeckError |
@@ -550,6 +549,12 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
             GeneratorResumedAfterReturn |
             GeneratorResumedAfterPanic |
             InfiniteLoop => {}
+            Panic { ref msg, ref file, line, col } => {
+                msg.hash_stable(hcx, hasher);
+                file.hash_stable(hcx, hasher);
+                line.hash_stable(hcx, hasher);
+                col.hash_stable(hcx, hasher);
+            },
             ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
             MachineError(ref err) => err.hash_stable(hcx, hasher),
             FunctionPointerTyMismatch(a, b) => {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index cf94a0fb4b4..8c300a0aba0 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -305,6 +305,8 @@ language_item_table! {
     PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
     PanicInfoLangItem,               "panic_info",              panic_info;
     PanicImplLangItem,               "panic_impl",              panic_impl;
+    // Libstd panic entry point. Necessary for const eval to be able to catch it
+    BeginPanicFnLangItem,            "begin_panic",             begin_panic_fn;
 
     ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
     BoxFreeFnLangItem,               "box_free",                box_free_fn;
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 1e9584bc55b..436478b8416 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -17,6 +17,7 @@ use errors::DiagnosticBuilder;
 
 use syntax_pos::Span;
 use syntax::ast;
+use syntax::symbol::Symbol;
 
 pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>;
 
@@ -250,7 +251,12 @@ pub enum EvalErrorKind<'tcx, O> {
     HeapAllocZeroBytes,
     HeapAllocNonPowerOfTwoAlignment(u64),
     Unreachable,
-    Panic,
+    Panic {
+        msg: Symbol,
+        line: u32,
+        col: u32,
+        file: Symbol,
+    },
     ReadFromReturnPointer,
     PathNotFound(Vec<String>),
     UnimplementedTraitSelection,
@@ -370,7 +376,7 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
                 "tried to re-, de-, or allocate heap memory with alignment that is not a power of two",
             Unreachable =>
                 "entered unreachable code",
-            Panic =>
+            Panic { .. } =>
                 "the evaluated program panicked",
             ReadFromReturnPointer =>
                 "tried to read from the return pointer",
@@ -465,6 +471,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
                 write!(f, "{}", inner),
             IncorrectAllocationInformation(size, size2, align, align2) =>
                 write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
+            Panic { ref msg, line, col, ref file } =>
+                write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
             _ => write!(f, "{}", self.description()),
         }
     }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index ad29f808285..95e2cc6c387 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -574,7 +574,11 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
             HeapAllocZeroBytes => HeapAllocZeroBytes,
             HeapAllocNonPowerOfTwoAlignment(n) => HeapAllocNonPowerOfTwoAlignment(n),
             Unreachable => Unreachable,
-            Panic => Panic,
+            Panic { ref msg, ref file, line, col } => Panic {
+                msg: msg.clone(),
+                file: file.clone(),
+                line, col,
+            },
             ReadFromReturnPointer => ReadFromReturnPointer,
             PathNotFound(ref v) => PathNotFound(v.clone()),
             UnimplementedTraitSelection => UnimplementedTraitSelection,
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 8aba4953123..a306a4d7c1e 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -5,13 +5,14 @@ use rustc::hir;
 use rustc::mir::interpret::ConstEvalErr;
 use rustc::mir;
 use rustc::ty::{self, TyCtxt, Instance};
-use rustc::ty::layout::{LayoutOf, Primitive, TyLayout};
+use rustc::ty::layout::{LayoutOf, Primitive, TyLayout, Size};
 use rustc::ty::subst::Subst;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 use syntax::ast::Mutability;
 use syntax::source_map::Span;
 use syntax::source_map::DUMMY_SP;
+use syntax::symbol::Symbol;
 
 use rustc::mir::interpret::{
     EvalResult, EvalError, EvalErrorKind, GlobalId,
@@ -19,7 +20,7 @@ use rustc::mir::interpret::{
 };
 use super::{
     Place, PlaceExtra, PlaceTy, MemPlace, OpTy, Operand, Value,
-    EvalContext, StackPopCleanup, Memory, MemoryKind
+    EvalContext, StackPopCleanup, Memory, MemoryKind, MPlaceTy,
 };
 
 pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
@@ -237,23 +238,56 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
         if !ecx.tcx.is_const_fn(instance.def_id()) {
             let def_id = instance.def_id();
             // Some fn calls are actually BinOp intrinsics
-            let (op, oflo) = if let Some(op) = ecx.tcx.is_binop_lang_item(def_id) {
-                op
+            let _: ! = if let Some((op, oflo)) = ecx.tcx.is_binop_lang_item(def_id) {
+                let (dest, bb) = destination.expect("128 lowerings can't diverge");
+                let l = ecx.read_value(args[0])?;
+                let r = ecx.read_value(args[1])?;
+                if oflo {
+                    ecx.binop_with_overflow(op, l, r, dest)?;
+                } else {
+                    ecx.binop_ignore_overflow(op, l, r, dest)?;
+                }
+                ecx.goto_block(bb);
+                return Ok(true);
+            } else if Some(def_id) == ecx.tcx.lang_items().panic_fn() {
+                assert!(args.len() == 1);
+                // &(&'static str, &'static str, u32, u32)
+                let ptr = ecx.read_value(args[0])?;
+                let place = ecx.ref_to_mplace(ptr)?;
+                let (msg, file, line, col) = (
+                    place_field(ecx, 0, place)?,
+                    place_field(ecx, 1, place)?,
+                    place_field(ecx, 2, place)?,
+                    place_field(ecx, 3, place)?,
+                );
+
+                let msg = to_str(ecx, msg)?;
+                let file = to_str(ecx, file)?;
+                let line = to_u32(line)?;
+                let col = to_u32(col)?;
+                return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
+            } else if Some(def_id) == ecx.tcx.lang_items().begin_panic_fn() {
+                assert!(args.len() == 2);
+                // &'static str, &(&'static str, u32, u32)
+                let msg = ecx.read_value(args[0])?;
+                let ptr = ecx.read_value(args[1])?;
+                let place = ecx.ref_to_mplace(ptr)?;
+                let (file, line, col) = (
+                    place_field(ecx, 0, place)?,
+                    place_field(ecx, 1, place)?,
+                    place_field(ecx, 2, place)?,
+                );
+
+                let msg = to_str(ecx, msg.value)?;
+                let file = to_str(ecx, file)?;
+                let line = to_u32(line)?;
+                let col = to_u32(col)?;
+                return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
             } else {
                 return Err(
                     ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
                 );
             };
-            let (dest, bb) = destination.expect("128 lowerings can't diverge");
-            let l = ecx.read_value(args[0])?;
-            let r = ecx.read_value(args[1])?;
-            if oflo {
-                ecx.binop_with_overflow(op, l, r, dest)?;
-            } else {
-                ecx.binop_ignore_overflow(op, l, r, dest)?;
-            }
-            ecx.goto_block(bb);
-            return Ok(true);
         }
         let mir = match ecx.load_mir(instance.def) {
             Ok(mir) => mir,
@@ -412,6 +446,39 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
     }
 }
 
+fn place_field<'a, 'tcx, 'mir>(
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+    i: u64,
+    place: MPlaceTy<'tcx>,
+) -> EvalResult<'tcx, Value> {
+    let place = ecx.mplace_field(place, i)?;
+    Ok(ecx.try_read_value_from_mplace(place)?.expect("bad panic arg layout"))
+}
+
+fn to_str<'a, 'tcx, 'mir>(
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+    val: Value,
+) -> EvalResult<'tcx, Symbol> {
+    if let Value::ScalarPair(ptr, len) = val {
+        let len = len.not_undef()?.to_bits(ecx.memory.pointer_size())?;
+        let bytes = ecx.memory.read_bytes(ptr.not_undef()?, Size::from_bytes(len as u64))?;
+        let str = ::std::str::from_utf8(bytes).map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
+        Ok(Symbol::intern(str))
+    } else {
+        bug!("panic arg is not a str")
+    }
+}
+
+fn to_u32<'a, 'tcx, 'mir>(
+    val: Value,
+) -> EvalResult<'tcx, u32> {
+    if let Value::Scalar(n) = val {
+        Ok(n.not_undef()?.to_bits(Size::from_bits(32))? as u32)
+    } else {
+        bug!("panic arg is not a str")
+    }
+}
+
 /// Project to a field of a (variant of a) const
 pub fn const_field<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index df3dc44b229..d9e7f33e836 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -213,7 +213,7 @@ fn from_known_layout<'tcx>(
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Try reading a value in memory; this is interesting particularily for ScalarPair.
     /// Return None if the layout does not permit loading this as a value.
-    fn try_read_value_from_mplace(
+    pub(super) fn try_read_value_from_mplace(
         &self,
         mplace: MPlaceTy<'tcx>,
     ) -> EvalResult<'tcx, Option<Value>> {
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 3f77e69b7dc..fa11e6f0719 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -230,7 +230,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
                     // FIXME: implement
                     => {},
 
-                    | Panic
+                    | Panic { .. }
                     | BoundsCheck{..}
                     | Overflow(_)
                     | OverflowNeg
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index d876ee77e76..20525b5f484 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -400,6 +400,11 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
         (self.qualif, Lrc::new(promoted_temps))
     }
+
+    fn is_const_panic_fn(&self, def_id: DefId) -> bool {
+        Some(def_id) == self.tcx.lang_items().panic_fn() ||
+        Some(def_id) == self.tcx.lang_items().begin_panic_fn()
+    }
 }
 
 /// Accumulates an Rvalue or Call's effects in self.qualif.
@@ -834,7 +839,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                         }
                     }
                     _ => {
-                        if self.tcx.is_const_fn(def_id) {
+                        if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) {
                             is_const_fn = Some(def_id);
                         }
                     }
@@ -880,8 +885,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
             // Const fn calls.
             if let Some(def_id) = is_const_fn {
+                // check the const_panic feature gate or
                 // find corresponding rustc_const_unstable feature
-                if let Some(&attr::Stability {
+                // FIXME: cannot allow this inside `allow_internal_unstable` because that would make
+                // `panic!` insta stable in constants, since the macro is marked with the attr
+                if self.is_const_panic_fn(def_id) {
+                    if self.mode == Mode::Fn {
+                        // never promote panics
+                        self.qualif = Qualif::NOT_CONST;
+                    } else if !self.tcx.sess.features_untracked().const_panic {
+                        // don't allow panics in constants without the feature gate
+                        emit_feature_err(
+                            &self.tcx.sess.parse_sess,
+                            "const_panic",
+                            self.span,
+                            GateIssue::Language,
+                            &format!("panicking in {}s is unstable", self.mode),
+                        );
+                    }
+                } else if let Some(&attr::Stability {
                     rustc_const_unstable: Some(attr::RustcConstUnstable {
                         feature: ref feature_name
                     }),
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 283fd36af41..862f0fd71b0 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -397,6 +397,7 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! {
 #[unstable(feature = "libstd_sys_internals",
            reason = "used by the panic! macro",
            issue = "0")]
+#[cfg_attr(not(any(stage0, test)), lang = "begin_panic")]
 #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
 pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {
     // Note that this should be the only allocation performed in this code path.
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 71ad118ed8e..4a819814d81 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -224,6 +224,9 @@ declare_features! (
     // Allows comparing raw pointers during const eval
     (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
 
+    // Allows panicking during const eval (produces compile-time errors)
+    (active, const_panic, "1.29.0", Some(51999), None),
+
     // Allows using #[prelude_import] on glob `use` items.
     //
     // rustc internal
diff --git a/src/test/ui/const-eval/const_panic.rs b/src/test/ui/const-eval/const_panic.rs
new file mode 100644
index 00000000000..f2170f509eb
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic.rs
@@ -0,0 +1,22 @@
+// 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(const_panic)]
+
+fn main() {}
+
+const Z: () = panic!("cheese");
+//~^ ERROR this constant cannot be used
+
+const Y: () = unreachable!();
+//~^ ERROR this constant cannot be used
+
+const X: () = unimplemented!();
+//~^ ERROR this constant cannot be used
diff --git a/src/test/ui/const-eval/const_panic.stderr b/src/test/ui/const-eval/const_panic.stderr
new file mode 100644
index 00000000000..c11146f4882
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic.stderr
@@ -0,0 +1,33 @@
+error: this constant cannot be used
+  --> $DIR/const_panic.rs:15:1
+   |
+LL | const Z: () = panic!("cheese");
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:15:15
+   |
+   = note: #[deny(const_err)] on by default
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic.rs:18:1
+   |
+LL | const Y: () = unreachable!();
+   | ^^^^^^^^^^^^^^--------------^
+   |               |
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:18:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic.rs:21:1
+   |
+LL | const X: () = unimplemented!();
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'not yet implemented', $DIR/const_panic.rs:21:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-eval/const_panic_libcore.rs b/src/test/ui/const-eval/const_panic_libcore.rs
new file mode 100644
index 00000000000..59aeca18129
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic_libcore.rs
@@ -0,0 +1,22 @@
+// 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.
+
+#![no_std]
+#![crate_type = "lib"]
+#![feature(const_panic)]
+
+const Z: () = panic!("cheese");
+//~^ ERROR this constant cannot be used
+
+const Y: () = unreachable!();
+//~^ ERROR this constant cannot be used
+
+const X: () = unimplemented!();
+//~^ ERROR this constant cannot be used
diff --git a/src/test/ui/const-eval/const_panic_libcore.stderr b/src/test/ui/const-eval/const_panic_libcore.stderr
new file mode 100644
index 00000000000..45f2ee7744e
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic_libcore.stderr
@@ -0,0 +1,33 @@
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore.rs:15:1
+   |
+LL | const Z: () = panic!("cheese");
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore.rs:15:15
+   |
+   = note: #[deny(const_err)] on by default
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore.rs:18:1
+   |
+LL | const Y: () = unreachable!();
+   | ^^^^^^^^^^^^^^--------------^
+   |               |
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore.rs:18:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore.rs:21:1
+   |
+LL | const X: () = unimplemented!();
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'not yet implemented', $DIR/const_panic_libcore.rs:21:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-eval/const_panic_libcore_main.rs b/src/test/ui/const-eval/const_panic_libcore_main.rs
new file mode 100644
index 00000000000..bbbe827a8ef
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic_libcore_main.rs
@@ -0,0 +1,35 @@
+// 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.
+
+#![crate_type = "bin"]
+#![feature(lang_items)]
+#![feature(panic_implementation)]
+#![feature(const_panic)]
+#![no_main]
+#![no_std]
+
+use core::panic::PanicInfo;
+
+const Z: () = panic!("cheese");
+//~^ ERROR this constant cannot be used
+
+const Y: () = unreachable!();
+//~^ ERROR this constant cannot be used
+
+const X: () = unimplemented!();
+//~^ ERROR this constant cannot be used
+
+#[lang = "eh_personality"]
+fn eh() {}
+
+#[panic_implementation]
+fn panic(_info: &PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/test/ui/const-eval/const_panic_libcore_main.stderr b/src/test/ui/const-eval/const_panic_libcore_main.stderr
new file mode 100644
index 00000000000..7cb9f51c427
--- /dev/null
+++ b/src/test/ui/const-eval/const_panic_libcore_main.stderr
@@ -0,0 +1,33 @@
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore_main.rs:20:1
+   |
+LL | const Z: () = panic!("cheese");
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_main.rs:20:15
+   |
+   = note: #[deny(const_err)] on by default
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore_main.rs:23:1
+   |
+LL | const Y: () = unreachable!();
+   | ^^^^^^^^^^^^^^--------------^
+   |               |
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_main.rs:23:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: this constant cannot be used
+  --> $DIR/const_panic_libcore_main.rs:26:1
+   |
+LL | const X: () = unimplemented!();
+   | ^^^^^^^^^^^^^^----------------^
+   |               |
+   |               the evaluated program panicked at 'not yet implemented', $DIR/const_panic_libcore_main.rs:26:15
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-eval/feature-gate-const_panic.rs b/src/test/ui/const-eval/feature-gate-const_panic.rs
new file mode 100644
index 00000000000..26eb95d9c66
--- /dev/null
+++ b/src/test/ui/const-eval/feature-gate-const_panic.rs
@@ -0,0 +1,20 @@
+// 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.
+
+fn main() {}
+
+const Z: () = panic!("cheese");
+//~^ ERROR panicking in constants is unstable
+
+const Y: () = unreachable!();
+//~^ ERROR panicking in constants is unstable
+
+const X: () = unimplemented!();
+//~^ ERROR panicking in constants is unstable
diff --git a/src/test/ui/const-eval/feature-gate-const_panic.stderr b/src/test/ui/const-eval/feature-gate-const_panic.stderr
new file mode 100644
index 00000000000..f4d05edd04a
--- /dev/null
+++ b/src/test/ui/const-eval/feature-gate-const_panic.stderr
@@ -0,0 +1,30 @@
+error[E0658]: panicking in constants is unstable (see issue #51999)
+  --> $DIR/feature-gate-const_panic.rs:13:15
+   |
+LL | const Z: () = panic!("cheese");
+   |               ^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_panic)] to the crate attributes to enable
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0658]: panicking in constants is unstable (see issue #51999)
+  --> $DIR/feature-gate-const_panic.rs:19:15
+   |
+LL | const X: () = unimplemented!();
+   |               ^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_panic)] to the crate attributes to enable
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0658]: panicking in constants is unstable (see issue #51999)
+  --> $DIR/feature-gate-const_panic.rs:16:15
+   |
+LL | const Y: () = unreachable!();
+   |               ^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_panic)] to the crate attributes to enable
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-32829.rs b/src/test/ui/issues/issue-32829.rs
index 60e83138c76..2d333f324c4 100644
--- a/src/test/ui/issues/issue-32829.rs
+++ b/src/test/ui/issues/issue-32829.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 static S : u64 = { { panic!("foo"); 0 } };
-//~^ ERROR calls in statics are limited
+//~^ ERROR panicking in statics is unstable
 
 fn main() {
     println!("{:?}", S);
diff --git a/src/test/ui/issues/issue-32829.stderr b/src/test/ui/issues/issue-32829.stderr
index 30b6a642904..55ee6d80d1f 100644
--- a/src/test/ui/issues/issue-32829.stderr
+++ b/src/test/ui/issues/issue-32829.stderr
@@ -1,11 +1,12 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0658]: panicking in statics is unstable (see issue #51999)
   --> $DIR/issue-32829.rs:11:22
    |
 LL | static S : u64 = { { panic!("foo"); 0 } };
    |                      ^^^^^^^^^^^^^^
    |
+   = help: add #![feature(const_panic)] to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0658`.