diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 4f36c3888b961..f195775bf86e9 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 fd4ba1d75625a..999e3d89fc7e4 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>, - return_qualif: Option, + local_qualif: IndexVec>, qualif: Qualif, const_fn_arg_vars: BitVector, temp_promotion_state: IndexVec, @@ -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| { @@ -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 709c3653b0267..3a02646d0af5f 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 83166c9bd4b5e..f80d55cb34267 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 707037911015c..cfa4b778dde80 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 802e660b9048d..f974a24c26f72 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 c3d5975fe01f6..fce1688716d30 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 48877a60d2504..d985bae1f2477 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 35e57dffb6c45..7194c159c1e98 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 e1f7f64e01a66..af1f6ef5ed4ac 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 9a84322ad063b..2b223bac8e67b 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 0000000000000..e233107169c75 --- /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 or the MIT license +// , 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 0000000000000..b5a9bfb45a1b4 --- /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 or the MIT license +// , 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 0000000000000..8b832976aab0e --- /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 or the MIT license +// , 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 0000000000000..27796a5feea28 --- /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 or the MIT license +// , 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 0000000000000..8c153315c25aa --- /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 or the MIT license +// , 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 0000000000000..602d4da24f383 --- /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 or the MIT license +// , 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 0000000000000..86e3482fda6b9 --- /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 9e09f66776c9b..17dc9f94fe19c 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 767f28ff7b190..29edc2756afff 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 `>::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 0000000000000..05d02e62bc871 --- /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 or the MIT license +// , 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 0000000000000..6a7f6255678ff --- /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`.