about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-05-22 12:57:06 +0000
committerbors <bors@rust-lang.org>2018-05-22 12:57:06 +0000
commit9f80ea32811db0bdbd05b1bef59f5db26b3e24a9 (patch)
tree6a347360749ddc9462a714f5cc00ffdd0efd0cdb /src
parentff8fa5cc69db5567b32ceca1ee4ac0dcfa3a81bc (diff)
parent2483c812176c8ecca54207517a2ba5500805b205 (diff)
downloadrust-9f80ea32811db0bdbd05b1bef59f5db26b3e24a9.tar.gz
rust-9f80ea32811db0bdbd05b1bef59f5db26b3e24a9.zip
Auto merge of #49172 - oli-obk:const_let, r=eddyb
Allow let bindings and destructuring in constants and const fn

r? @eddyb

cc https://github.com/rust-lang/rust/issues/48821
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/diagnostics.rs15
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs134
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/compile-fail/const-block-non-item-statement-2.rs12
-rw-r--r--src/test/compile-fail/const-block-non-item-statement-3.rs6
-rw-r--r--src/test/compile-fail/const-block-non-item-statement.rs6
-rw-r--r--src/test/compile-fail/const-fn-destructuring-arg.rs10
-rw-r--r--src/test/compile-fail/const-fn-not-safe-for-const.rs10
-rw-r--r--src/test/compile-fail/issue-18118.rs7
-rw-r--r--src/test/compile-fail/issue-37550.rs8
-rw-r--r--src/test/compile-fail/issue32829.rs25
-rw-r--r--src/test/run-pass/ctfe/const-block-non-item-statement-3.rs15
-rw-r--r--src/test/run-pass/ctfe/const-block-non-item-statement.rs17
-rw-r--r--src/test/run-pass/ctfe/const-fn-destructuring-arg.rs23
-rw-r--r--src/test/run-pass/ctfe/issue-37550.rs18
-rw-r--r--src/test/run-pass/ctfe/locals-in-const-fn.rs45
-rw-r--r--src/test/ui/const-eval/const_let.rs30
-rw-r--r--src/test/ui/const-eval/const_let.stderr15
-rw-r--r--src/test/ui/const-fn-error.rs3
-rw-r--r--src/test/ui/const-fn-error.stderr24
-rw-r--r--src/test/ui/feature-gate-const_let.rs22
-rw-r--r--src/test/ui/feature-gate-const_let.stderr19
22 files changed, 354 insertions, 113 deletions
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 4f36c3888b9..f195775bf86 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -597,21 +597,6 @@ See [RFC 911] for more details on the design of `const fn`s.
 [RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
 "##,
 
-E0016: r##"
-Blocks in constants may only contain items (such as constant, function
-definition, etc...) and a tail expression. Erroneous code example:
-
-```compile_fail,E0016
-const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
-```
-
-To avoid it, you have to replace the non-item object:
-
-```
-const FOO: i32 = { const X : i32 = 0; X };
-```
-"##,
-
 E0017: r##"
 References in statics and constants may only refer to immutable values.
 Erroneous code example:
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index fd4ba1d7562..999e3d89fc7 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -32,7 +32,7 @@ use rustc::middle::lang_items;
 use rustc_target::spec::abi::Abi;
 use syntax::attr;
 use syntax::ast::LitKind;
-use syntax::feature_gate::UnstableFeatures;
+use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue};
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::fmt;
@@ -120,8 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     rpo: ReversePostorder<'a, 'tcx>,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    temp_qualif: IndexVec<Local, Option<Qualif>>,
-    return_qualif: Option<Qualif>,
+    local_qualif: IndexVec<Local, Option<Qualif>>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
     temp_promotion_state: IndexVec<Local, TempState>,
@@ -140,11 +139,11 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
         let param_env = tcx.param_env(def_id);
 
-        let mut temp_qualif = IndexVec::from_elem(None, &mir.local_decls);
+        let mut local_qualif = IndexVec::from_elem(None, &mir.local_decls);
         for arg in mir.args_iter() {
             let mut qualif = Qualif::NEEDS_DROP;
             qualif.restrict(mir.local_decls[arg].ty, tcx, param_env);
-            temp_qualif[arg] = Some(qualif);
+            local_qualif[arg] = Some(qualif);
         }
 
         Qualifier {
@@ -155,8 +154,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             rpo,
             tcx,
             param_env,
-            temp_qualif,
-            return_qualif: None,
+            local_qualif,
             qualif: Qualif::empty(),
             const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
             temp_promotion_state: temps,
@@ -191,12 +189,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     fn statement_like(&mut self) {
         self.add(Qualif::NOT_CONST);
         if self.mode != Mode::Fn {
-            let mut err = struct_span_err!(
-                self.tcx.sess,
+            let mut err = feature_err(
+                &self.tcx.sess.parse_sess,
+                "const_let",
                 self.span,
-                E0016,
-                "blocks in {}s are limited to items and tail expressions",
-                self.mode
+                GateIssue::Language,
+                &format!("statements in {}s are unstable", self.mode),
             );
             if self.tcx.sess.teach(&err.get_code().unwrap()) {
                 err.note("Blocks in constants may only contain items (such as constant, function \
@@ -266,6 +264,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
     /// Assign the current qualification to the given destination.
     fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
+        trace!("assign: {:?}", dest);
         let qualif = self.qualif;
         let span = self.span;
         let store = |slot: &mut Option<Qualif>| {
@@ -281,20 +280,23 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 if self.mir.local_kind(index) == LocalKind::Temp
                 && self.temp_promotion_state[index].is_promotable() {
                     debug!("store to promotable temp {:?}", index);
-                    store(&mut self.temp_qualif[index]);
+                    store(&mut self.local_qualif[index]);
                 }
             }
             return;
         }
 
         match *dest {
-            Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
-                debug!("store to temp {:?}", index);
-                store(&mut self.temp_qualif[index])
+            Place::Local(index) if (self.mir.local_kind(index) == LocalKind::Var ||
+                                   self.mir.local_kind(index) == LocalKind::Arg) &&
+                                   self.tcx.sess.features_untracked().const_let => {
+                debug!("store to var {:?}", index);
+                self.local_qualif[index] = Some(self.qualif);
             }
-            Place::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
-                debug!("store to return place {:?}", index);
-                store(&mut self.return_qualif)
+            Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp ||
+                                   self.mir.local_kind(index) == LocalKind::ReturnPointer => {
+                debug!("store to {:?} (temp or return pointer)", index);
+                store(&mut self.local_qualif[index])
             }
 
             Place::Projection(box Projection {
@@ -302,7 +304,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 elem: ProjectionElem::Deref
             }) if self.mir.local_kind(index) == LocalKind::Temp
                && self.mir.local_decls[index].ty.is_box()
-               && self.temp_qualif[index].map_or(false, |qualif| {
+               && self.local_qualif[index].map_or(false, |qualif| {
                     qualif.intersects(Qualif::NOT_CONST)
                }) => {
                 // Part of `box expr`, we should've errored
@@ -355,40 +357,42 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 TerminatorKind::FalseUnwind { .. } => None,
 
                 TerminatorKind::Return => {
-                    // Check for unused values. This usually means
-                    // there are extra statements in the AST.
-                    for temp in mir.temps_iter() {
-                        if self.temp_qualif[temp].is_none() {
-                            continue;
-                        }
-
-                        let state = self.temp_promotion_state[temp];
-                        if let TempState::Defined { location, uses: 0 } = state {
-                            let data = &mir[location.block];
-                            let stmt_idx = location.statement_index;
-
-                            // Get the span for the initialization.
-                            let source_info = if stmt_idx < data.statements.len() {
-                                data.statements[stmt_idx].source_info
-                            } else {
-                                data.terminator().source_info
-                            };
-                            self.span = source_info.span;
+                    if !self.tcx.sess.features_untracked().const_let {
+                        // Check for unused values. This usually means
+                        // there are extra statements in the AST.
+                        for temp in mir.temps_iter() {
+                            if self.local_qualif[temp].is_none() {
+                                continue;
+                            }
 
-                            // Treat this as a statement in the AST.
-                            self.statement_like();
+                            let state = self.temp_promotion_state[temp];
+                            if let TempState::Defined { location, uses: 0 } = state {
+                                let data = &mir[location.block];
+                                let stmt_idx = location.statement_index;
+
+                                // Get the span for the initialization.
+                                let source_info = if stmt_idx < data.statements.len() {
+                                    data.statements[stmt_idx].source_info
+                                } else {
+                                    data.terminator().source_info
+                                };
+                                self.span = source_info.span;
+
+                                // Treat this as a statement in the AST.
+                                self.statement_like();
+                            }
                         }
-                    }
 
-                    // Make sure there are no extra unassigned variables.
-                    self.qualif = Qualif::NOT_CONST;
-                    for index in mir.vars_iter() {
-                        if !self.const_fn_arg_vars.contains(index.index()) {
-                            debug!("unassigned variable {:?}", index);
-                            self.assign(&Place::Local(index), Location {
-                                block: bb,
-                                statement_index: usize::MAX,
-                            });
+                        // Make sure there are no extra unassigned variables.
+                        self.qualif = Qualif::NOT_CONST;
+                        for index in mir.vars_iter() {
+                            if !self.const_fn_arg_vars.contains(index.index()) {
+                                debug!("unassigned variable {:?}", index);
+                                self.assign(&Place::Local(index), Location {
+                                    block: bb,
+                                    statement_index: usize::MAX,
+                                });
+                            }
                         }
                     }
 
@@ -408,7 +412,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             }
         }
 
-        self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
+        self.qualif = self.local_qualif[RETURN_PLACE].unwrap_or(Qualif::NOT_CONST);
 
         // Account for errors in consts by using the
         // conservative type qualification instead.
@@ -453,9 +457,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             LocalKind::ReturnPointer => {
                 self.not_const();
             }
-            LocalKind::Var => {
+            LocalKind::Var if !self.tcx.sess.features_untracked().const_let => {
+                if self.mode != Mode::Fn {
+                    emit_feature_err(&self.tcx.sess.parse_sess, "const_let",
+                                    self.span, GateIssue::Language,
+                                    &format!("let bindings in {}s are unstable",self.mode));
+                }
                 self.add(Qualif::NOT_CONST);
             }
+            LocalKind::Var |
             LocalKind::Arg |
             LocalKind::Temp => {
                 if let LocalKind::Arg = kind {
@@ -466,7 +476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     self.add(Qualif::NOT_PROMOTABLE);
                 }
 
-                if let Some(qualif) = self.temp_qualif[local] {
+                if let Some(qualif) = self.local_qualif[local] {
                     self.add(qualif);
                 } else {
                     self.not_const();
@@ -588,7 +598,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Operand::Move(Place::Local(local)) = *operand {
-                    self.temp_qualif[local] = self.temp_qualif[local].map(|q|
+                    self.local_qualif[local] = self.local_qualif[local].map(|q|
                         q - Qualif::NEEDS_DROP
                     );
                 }
@@ -759,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     }
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
-                            if let Some(qualif) = self.temp_qualif[local] {
+                            if let Some(qualif) = self.local_qualif[local] {
                                 // `forbidden_mut` is false, so we can safely ignore
                                 // `MUTABLE_INTERIOR` from the local's qualifications.
                                 // This allows borrowing fields which don't have
@@ -1033,7 +1043,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                 // HACK(eddyb) Emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place::Local(local) = *place {
-                    if self.temp_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
+                    if self.local_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
                         Some(self.mir.local_decls[local].source_info.span)
                     } else {
                         None
@@ -1070,7 +1080,8 @@ This does not pose a problem by itself because they can't be accessed directly."
         // Check the allowed const fn argument forms.
         if let (Mode::ConstFn, &Place::Local(index)) = (self.mode, dest) {
             if self.mir.local_kind(index) == LocalKind::Var &&
-               self.const_fn_arg_vars.insert(index.index()) {
+               self.const_fn_arg_vars.insert(index.index()) &&
+               !self.tcx.sess.features_untracked().const_let {
 
                 // Direct use of an argument is permitted.
                 match *rvalue {
@@ -1086,10 +1097,11 @@ This does not pose a problem by itself because they can't be accessed directly."
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
                     let decl = &self.mir.local_decls[index];
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
+                    let mut err = feature_err(
+                        &self.tcx.sess.parse_sess,
+                        "const_let",
                         decl.source_info.span,
-                        E0022,
+                        GateIssue::Language,
                         "arguments of constant functions can only be immutable by-value bindings"
                     );
                     if self.tcx.sess.teach(&err.get_code().unwrap()) {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 709c3653b02..3a02646d0af 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -214,6 +214,9 @@ declare_features! (
     // Allows the definition of `const fn` functions.
     (active, const_fn, "1.2.0", Some(24111), None),
 
+    // Allows let bindings and destructuring in `const fn` functions and constants.
+    (active, const_let, "1.22.1", Some(48821), None),
+
     // Allows using #[prelude_import] on glob `use` items.
     //
     // rustc internal
diff --git a/src/test/compile-fail/const-block-non-item-statement-2.rs b/src/test/compile-fail/const-block-non-item-statement-2.rs
index 83166c9bd4b..f80d55cb342 100644
--- a/src/test/compile-fail/const-block-non-item-statement-2.rs
+++ b/src/test/compile-fail/const-block-non-item-statement-2.rs
@@ -9,18 +9,20 @@
 // except according to those terms.
 
 const A: usize = { 1; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^ ERROR statements in constants are unstable
 
 const B: usize = { { } 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^ ERROR statements in constants are unstable
 
 macro_rules! foo {
-    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
+    () => (()) //~ ERROR statements in constants are unstable
 }
 const C: usize = { foo!(); 2 };
 
 const D: usize = { let x = 4; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
+//~^ ERROR let bindings in constants are unstable
+//~| ERROR statements in constants are unstable
+//~| ERROR let bindings in constants are unstable
+//~| ERROR statements in constants are unstable
 
 pub fn main() {}
diff --git a/src/test/compile-fail/const-block-non-item-statement-3.rs b/src/test/compile-fail/const-block-non-item-statement-3.rs
index 70703791101..cfa4b778dde 100644
--- a/src/test/compile-fail/const-block-non-item-statement-3.rs
+++ b/src/test/compile-fail/const-block-non-item-statement-3.rs
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 type Array = [u32; {  let x = 2; 5 }];
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
+//~^ ERROR let bindings in constants are unstable
+//~| ERROR statements in constants are unstable
+//~| ERROR let bindings in constants are unstable
+//~| ERROR statements in constants are unstable
 
 pub fn main() {}
diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs
index 802e660b904..f974a24c26f 100644
--- a/src/test/compile-fail/const-block-non-item-statement.rs
+++ b/src/test/compile-fail/const-block-non-item-statement.rs
@@ -10,8 +10,10 @@
 
 enum Foo {
     Bar = { let x = 1; 3 }
-    //~^ ERROR: blocks in constants are limited to items and tail expressions
-    //~^^ ERROR: blocks in constants are limited to items and tail expressions
+    //~^ ERROR let bindings in constants are unstable
+    //~| ERROR statements in constants are unstable
+    //~| ERROR let bindings in constants are unstable
+    //~| ERROR statements in constants are unstable
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/const-fn-destructuring-arg.rs b/src/test/compile-fail/const-fn-destructuring-arg.rs
index c3d5975fe01..fce1688716d 100644
--- a/src/test/compile-fail/const-fn-destructuring-arg.rs
+++ b/src/test/compile-fail/const-fn-destructuring-arg.rs
@@ -8,16 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// test that certain things are disallowed in const fn signatures
+// test that certain things are disallowed in constant functions
 
 #![feature(const_fn)]
 
 // no destructuring
 const fn i((
-            a, //~ ERROR: E0022
-            b  //~ ERROR: E0022
+            a,
+            //~^ ERROR arguments of constant functions can only be immutable by-value bindings
+            b
+            //~^ ERROR arguments of constant functions can only be immutable by-value bindings
            ): (u32, u32)) -> u32 {
     a + b
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR let bindings in constant functions are unstable
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/const-fn-not-safe-for-const.rs b/src/test/compile-fail/const-fn-not-safe-for-const.rs
index 48877a60d25..d985bae1f24 100644
--- a/src/test/compile-fail/const-fn-not-safe-for-const.rs
+++ b/src/test/compile-fail/const-fn-not-safe-for-const.rs
@@ -38,9 +38,15 @@ const fn get_Y_addr() -> &'static u32 {
 }
 
 const fn get() -> u32 {
-    let x = 22; //~ ERROR E0016
-    let y = 44; //~ ERROR E0016
+    let x = 22;
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR statements in constant functions are unstable
+    let y = 44;
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR statements in constant functions are unstable
     x + y
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR let bindings in constant functions are unstable
 }
 
 fn main() {
diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs
index 35e57dffb6c..7194c159c1e 100644
--- a/src/test/compile-fail/issue-18118.rs
+++ b/src/test/compile-fail/issue-18118.rs
@@ -10,9 +10,12 @@
 
 pub fn main() {
     const z: &'static isize = {
-        //~^ ERROR blocks in constants are limited to items and tail expressions
+        //~^ ERROR let bindings in constants are unstable
+        //~| ERROR statements in constants are unstable
         let p = 3;
-        //~^ ERROR blocks in constants are limited to items and tail expressions
+        //~^ ERROR let bindings in constants are unstable
+        //~| ERROR statements in constants are unstable
         &p //~ ERROR `p` does not live long enough
+        //~^ ERROR let bindings in constants are unstable
     };
 }
diff --git a/src/test/compile-fail/issue-37550.rs b/src/test/compile-fail/issue-37550.rs
index e1f7f64e01a..af1f6ef5ed4 100644
--- a/src/test/compile-fail/issue-37550.rs
+++ b/src/test/compile-fail/issue-37550.rs
@@ -11,8 +11,12 @@
 #![feature(const_fn)]
 
 const fn x() {
-    let t = true; //~ ERROR blocks in constant functions are limited to items and tail expressions
-    let x = || t; //~ ERROR blocks in constant functions are limited to items and tail expressions
+    let t = true;
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR statements in constant functions are unstable
+    let x = || t;
+    //~^ ERROR let bindings in constant functions are unstable
+    //~| ERROR statements in constant functions are unstable
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue32829.rs b/src/test/compile-fail/issue32829.rs
index 9a84322ad06..2b223bac8e6 100644
--- a/src/test/compile-fail/issue32829.rs
+++ b/src/test/compile-fail/issue32829.rs
@@ -14,7 +14,8 @@
 
 const bad : u32 = {
     {
-        5; //~ ERROR: blocks in constants are limited to items and tail expressions
+        5;
+        //~^ ERROR statements in constants are unstable
         0
     }
 };
@@ -22,7 +23,7 @@ const bad : u32 = {
 const bad_two : u32 = {
     {
         invalid();
-        //~^ ERROR: blocks in constants are limited to items and tail expressions
+        //~^ ERROR statements in constants are unstable
         //~^^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants
         0
     }
@@ -31,14 +32,15 @@ const bad_two : u32 = {
 const bad_three : u32 = {
     {
         valid();
-        //~^ ERROR: blocks in constants are limited to items and tail expressions
+        //~^ ERROR statements in constants are unstable
         0
     }
 };
 
 static bad_four : u32 = {
     {
-        5; //~ ERROR: blocks in statics are limited to items and tail expressions
+        5;
+        //~^ ERROR statements in statics are unstable
         0
     }
 };
@@ -46,8 +48,8 @@ static bad_four : u32 = {
 static bad_five : u32 = {
     {
         invalid();
-        //~^ ERROR: blocks in statics are limited to items and tail expressions
-        //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~| ERROR statements in statics are unstable
         0
     }
 };
@@ -55,14 +57,15 @@ static bad_five : u32 = {
 static bad_six : u32 = {
     {
         valid();
-        //~^ ERROR: blocks in statics are limited to items and tail expressions
+        //~^ ERROR statements in statics are unstable
         0
     }
 };
 
 static mut bad_seven : u32 = {
     {
-        5; //~ ERROR: blocks in statics are limited to items and tail expressions
+        5;
+        //~^ ERROR statements in statics are unstable
         0
     }
 };
@@ -70,8 +73,8 @@ static mut bad_seven : u32 = {
 static mut bad_eight : u32 = {
     {
         invalid();
-        //~^ ERROR: blocks in statics are limited to items and tail expressions
-        //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR statements in statics are unstable
+        //~| ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
         0
     }
 };
@@ -79,7 +82,7 @@ static mut bad_eight : u32 = {
 static mut bad_nine : u32 = {
     {
         valid();
-        //~^ ERROR: blocks in statics are limited to items and tail expressions
+        //~^ ERROR statements in statics are unstable
         0
     }
 };
diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs b/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs
new file mode 100644
index 00000000000..e233107169c
--- /dev/null
+++ b/src/test/run-pass/ctfe/const-block-non-item-statement-3.rs
@@ -0,0 +1,15 @@
+// Copyright 2014 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_let)]
+
+type Array = [u32; {  let x = 2; 5 }];
+
+pub fn main() {}
diff --git a/src/test/run-pass/ctfe/const-block-non-item-statement.rs b/src/test/run-pass/ctfe/const-block-non-item-statement.rs
new file mode 100644
index 00000000000..b5a9bfb45a1
--- /dev/null
+++ b/src/test/run-pass/ctfe/const-block-non-item-statement.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 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_let)]
+
+enum Foo {
+    Bar = { let x = 1; 3 }
+}
+
+pub fn main() {}
diff --git a/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs b/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs
new file mode 100644
index 00000000000..8b832976aab
--- /dev/null
+++ b/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// test that certain things are disallowed in constant functions
+
+#![feature(const_fn, const_let)]
+
+// no destructuring
+const fn i((
+            a,
+            b
+           ): (u32, u32)) -> u32 {
+    a + b
+}
+
+fn main() {}
diff --git a/src/test/run-pass/ctfe/issue-37550.rs b/src/test/run-pass/ctfe/issue-37550.rs
new file mode 100644
index 00000000000..27796a5feea
--- /dev/null
+++ b/src/test/run-pass/ctfe/issue-37550.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 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_fn, const_let)]
+
+const fn x() {
+    let t = true;
+    let x = || t;
+}
+
+fn main() {}
diff --git a/src/test/run-pass/ctfe/locals-in-const-fn.rs b/src/test/run-pass/ctfe/locals-in-const-fn.rs
new file mode 100644
index 00000000000..8c153315c25
--- /dev/null
+++ b/src/test/run-pass/ctfe/locals-in-const-fn.rs
@@ -0,0 +1,45 @@
+// 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.
+
+// https://github.com/rust-lang/rust/issues/48821
+
+#![feature(const_fn, const_let)]
+
+const fn foo(i: usize) -> usize {
+    let x = i;
+    x
+}
+
+static FOO: usize = foo(42);
+
+const fn bar(mut i: usize) -> usize {
+    i += 8;
+    let x = &i;
+    *x
+}
+
+static BAR: usize = bar(42);
+
+const fn boo(mut i: usize) -> usize {
+    {
+        let mut x = i;
+        x += 10;
+        i = x;
+    }
+    i
+}
+
+static BOO: usize = boo(42);
+
+fn main() {
+    assert!(FOO == 42);
+    assert!(BAR == 50);
+    assert!(BOO == 52);
+}
diff --git a/src/test/ui/const-eval/const_let.rs b/src/test/ui/const-eval/const_let.rs
new file mode 100644
index 00000000000..602d4da24f3
--- /dev/null
+++ b/src/test/ui/const-eval/const_let.rs
@@ -0,0 +1,30 @@
+// 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_let)]
+
+fn main() {}
+
+struct FakeNeedsDrop;
+
+impl Drop for FakeNeedsDrop {
+    fn drop(&mut self) {}
+}
+
+// ok
+const X: FakeNeedsDrop = { let x = FakeNeedsDrop; x };
+
+// error
+const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
+//~^ ERROR constant contains unimplemented expression type
+
+// error
+const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
+//~^ ERROR constant contains unimplemented expression type
diff --git a/src/test/ui/const-eval/const_let.stderr b/src/test/ui/const-eval/const_let.stderr
new file mode 100644
index 00000000000..86e3482fda6
--- /dev/null
+++ b/src/test/ui/const-eval/const_let.stderr
@@ -0,0 +1,15 @@
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/const_let.rs:25:55
+   |
+LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
+   |                                                       ^
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/const_let.rs:29:35
+   |
+LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
+   |                                   ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0019`.
diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs
index 9e09f66776c..17dc9f94fe1 100644
--- a/src/test/ui/const-fn-error.rs
+++ b/src/test/ui/const-fn-error.rs
@@ -14,7 +14,8 @@ const X : usize = 2;
 
 const fn f(x: usize) -> usize {
     let mut sum = 0;
-    //~^ ERROR E0016
+    //~^ let bindings in constant functions are unstable
+    //~| statements in constant functions are unstable
     for i in 0..x {
         //~^ ERROR E0015
         //~| ERROR E0019
diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr
index 767f28ff7b1..29edc2756af 100644
--- a/src/test/ui/const-fn-error.stderr
+++ b/src/test/ui/const-fn-error.stderr
@@ -1,23 +1,33 @@
-error[E0016]: blocks in constant functions are limited to items and tail expressions
+error[E0658]: let bindings in constant functions are unstable (see issue #48821)
   --> $DIR/const-fn-error.rs:16:19
    |
 LL |     let mut sum = 0;
    |                   ^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
+
+error[E0658]: statements in constant functions are unstable (see issue #48821)
+  --> $DIR/const-fn-error.rs:16:19
+   |
+LL |     let mut sum = 0;
+   |                   ^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
 
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-fn-error.rs:18:14
+  --> $DIR/const-fn-error.rs:19:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0019]: constant function contains unimplemented expression type
-  --> $DIR/const-fn-error.rs:18:14
+  --> $DIR/const-fn-error.rs:19:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0080]: constant evaluation error
-  --> $DIR/const-fn-error.rs:18:14
+  --> $DIR/const-fn-error.rs:19:14
    |
 LL |     for i in 0..x {
    |              ^^^^ calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
@@ -26,12 +36,12 @@ LL |     let a : [i32; f(X)];
    |                   ---- inside call to `f`
    |
 note: for constant expression here
-  --> $DIR/const-fn-error.rs:29:13
+  --> $DIR/const-fn-error.rs:30:13
    |
 LL |     let a : [i32; f(X)];
    |             ^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
-Some errors occurred: E0015, E0016, E0019, E0080.
+Some errors occurred: E0015, E0019, E0080, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/feature-gate-const_let.rs b/src/test/ui/feature-gate-const_let.rs
new file mode 100644
index 00000000000..05d02e62bc8
--- /dev/null
+++ b/src/test/ui/feature-gate-const_let.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.
+
+// Test use of const let without feature gate.
+
+#![feature(const_fn)]
+
+const fn foo() -> usize {
+    let x = 42;
+    //~^ ERROR statements in constant functions are unstable
+    //~| ERROR: let bindings in constant functions are unstable
+    42
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gate-const_let.stderr b/src/test/ui/feature-gate-const_let.stderr
new file mode 100644
index 00000000000..6a7f6255678
--- /dev/null
+++ b/src/test/ui/feature-gate-const_let.stderr
@@ -0,0 +1,19 @@
+error[E0658]: let bindings in constant functions are unstable (see issue #48821)
+  --> $DIR/feature-gate-const_let.rs:16:13
+   |
+LL |     let x = 42;
+   |             ^^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
+
+error[E0658]: statements in constant functions are unstable (see issue #48821)
+  --> $DIR/feature-gate-const_let.rs:16:13
+   |
+LL |     let x = 42;
+   |             ^^
+   |
+   = help: add #![feature(const_let)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.