diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 726e891df0ccf..d62f6b172580a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -120,7 +120,6 @@ #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] -#![feature(const_let)] #![feature(const_int_rotate)] #![feature(const_int_wrapping)] #![feature(const_int_sign)] diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 368f83eb61127..7b158c3958d4a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -149,6 +149,14 @@ pub struct Mir<'tcx> { /// This is used for the "rust-call" ABI. pub spread_arg: Option, + /// Mark this MIR of a const context other than const functions as having converted a `&&` or + /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop + /// this conversion from happening and use short circuiting, we will cause the following code + /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };` + /// + /// List of places where control flow was destroyed. Used for error reporting. + pub control_flow_destroyed: Vec<(Span, String)>, + /// A span representing this MIR, for error reporting pub span: Span, @@ -167,6 +175,7 @@ impl<'tcx> Mir<'tcx> { arg_count: usize, upvar_decls: Vec, span: Span, + control_flow_destroyed: Vec<(Span, String)>, ) -> Self { // We need `arg_count` locals, and one for the return place assert!( @@ -191,6 +200,7 @@ impl<'tcx> Mir<'tcx> { spread_arg: None, span, cache: cache::Cache::new(), + control_flow_destroyed, } } @@ -421,6 +431,7 @@ impl_stable_hash_for!(struct Mir<'tcx> { arg_count, upvar_decls, spread_arg, + control_flow_destroyed, span, cache }); @@ -1748,6 +1759,9 @@ pub enum StatementKind<'tcx> { /// (e.g. inspecting constants and discriminant values), and the /// kind of pattern it comes from. This is in order to adapt potential /// error messages to these specific patterns. + /// + /// Note that this also is emitted for regular `let` bindings to ensure that locals that are + /// never accessed still get some sanity checks for e.g. `let x: ! = ..;` FakeRead(FakeReadCause, Place<'tcx>), /// Write the discriminant for a variant to the enum Place. @@ -2972,6 +2986,7 @@ BraceStructTypeFoldableImpl! { arg_count, upvar_decls, spread_arg, + control_flow_destroyed, span, cache, } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d6aeb288b5cdc..1d28c4fa114ef 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -35,6 +35,7 @@ CloneTypeFoldableAndLiftImpls! { usize, ::ty::layout::VariantIdx, u64, + String, ::middle::region::Scope, ::syntax::ast::FloatTy, ::syntax::ast::NodeId, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d95a74be77696..80cab0cf68687 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -854,15 +854,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - Mir::new(self.cfg.basic_blocks, - self.source_scopes, - ClearCrossCrate::Set(self.source_scope_local_data), - IndexVec::new(), - yield_ty, - self.local_decls, - self.arg_count, - self.upvar_decls, - self.fn_span + Mir::new( + self.cfg.basic_blocks, + self.source_scopes, + ClearCrossCrate::Set(self.source_scope_local_data), + IndexVec::new(), + yield_ty, + self.local_decls, + self.arg_count, + self.upvar_decls, + self.fn_span, + self.hir.control_flow_destroyed(), ) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 2e9edf20c5708..81cccd9fd530b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -372,6 +372,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // FIXME(eddyb) use logical ops in constants when // they can handle that kind of control-flow. (hir::BinOpKind::And, hir::Constness::Const) => { + cx.control_flow_destroyed.push(( + op.span, + "`&&` operator".into(), + )); ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), @@ -379,6 +383,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } (hir::BinOpKind::Or, hir::Constness::Const) => { + cx.control_flow_destroyed.push(( + op.span, + "`||` operator".into(), + )); ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index c414088b65322..a7924b7b73876 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -56,6 +56,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// True if this constant/function needs overflow checks. check_overflow: bool, + + /// See field with the same name on `Mir` + control_flow_destroyed: Vec<(Span, String)>, } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { @@ -96,9 +99,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { constness, body_owner_kind, check_overflow, + control_flow_destroyed: Vec::new(), } } + pub fn control_flow_destroyed(self) -> Vec<(Span, String)> { + self.control_flow_destroyed + } } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 93bf1b3e36e38..9d90dc2931afa 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -219,7 +219,8 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], - span + span, + vec![], ); if let Some(..) = ty { @@ -387,7 +388,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { self.local_decls, self.sig.inputs().len(), vec![], - self.span + self.span, + vec![], ) } @@ -835,7 +837,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, local_decls, sig.inputs().len(), vec![], - span + span, + vec![], ); if let Abi::RustCall = sig.abi { mir.spread_arg = Some(Local::new(sig.inputs().len())); @@ -912,6 +915,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, local_decls, sig.inputs().len(), vec![], - span + span, + vec![], ) } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index c5add6260789a..15a82fcadc1f2 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -412,7 +412,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, initial_locals, 0, vec![], - mir.span + mir.span, + vec![], ), tcx, source: mir, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 09fe7b14c7973..cd6a9e98e8dad 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -552,7 +552,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.super_place(place, context, location); match proj.elem { ProjectionElem::Deref => { - this.add(Qualif::NOT_CONST); + if context.is_mutating_use() { + // `not_const` errors out in const contexts + this.not_const() + } else { + // just make sure this doesn't get promoted + this.add(Qualif::NOT_CONST); + } let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); match this.mode { Mode::Fn => {}, @@ -1159,7 +1165,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if self.mir.local_kind(index) == LocalKind::Var && self.const_fn_arg_vars.insert(index) && !self.tcx.features().const_let { - // Direct use of an argument is permitted. match *rvalue { Rvalue::Use(Operand::Copy(Place::Local(local))) | @@ -1170,7 +1175,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } _ => {} } - // Avoid a generic error for other uses of arguments. if self.qualif.contains(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; @@ -1329,6 +1333,37 @@ impl MirPass for QualifyAndPromoteConstants { // Do the actual promotion, now that we know what's viable. promote_consts::promote_candidates(mir, tcx, temps, candidates); } else { + if !mir.control_flow_destroyed.is_empty() { + let mut locals = mir.vars_iter(); + if let Some(local) = locals.next() { + let span = mir.local_decls[local].source_info.span; + let mut error = tcx.sess.struct_span_err( + span, + &format!( + "new features like let bindings are not permitted in {}s \ + which also use short circuiting operators", + mode, + ), + ); + for (span, kind) in mir.control_flow_destroyed.iter() { + error.span_note( + *span, + &format!("use of {} here does not actually short circuit due to \ + the const evaluator presently not being able to do control flow. \ + See https://github.com/rust-lang/rust/issues/49146 for more \ + information.", kind), + ); + } + for local in locals { + let span = mir.local_decls[local].source_info.span; + error.span_note( + span, + "more locals defined here", + ); + } + error.emit(); + } + } let promoted_temps = if mode == Mode::Const { // Already computed by `mir_const_qualif`. const_promoted_temps.unwrap() diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 13e134ba85928..9e5d75a746e85 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -229,7 +229,7 @@ fn check_statement( check_rvalue(tcx, mir, rval, span) } - StatementKind::FakeRead(..) => Err((span, "match in const fn is unstable".into())), + StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span, PlaceMode::Read), // just an assignment StatementKind::SetDiscriminant { .. } => Ok(()), diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 17dc9f94fe19c..397bc7efd633c 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(const_fn, const_let)] const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; - //~^ 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/run-pass/ctfe/const-fn-destructuring-arg.rs b/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs deleted file mode 100644 index 88f0d0714f9a1..0000000000000 --- a/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -// run-pass -#![allow(dead_code)] - -// 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/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs index ef0de61d219ad..63e5bcccf5d34 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs @@ -24,7 +24,7 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); static BAR: () = unsafe { - *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer + *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type }; fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index 0892b05a69df2..740954c6c6623 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -1,9 +1,9 @@ -error[E0080]: could not evaluate static initializer +error[E0019]: static contains unimplemented expression type --> $DIR/assign-to-static-within-other-static-2.rs:27:5 | -LL | *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer - | ^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer +LL | *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 01fcc8307c0c1..6c2fdcc8615c8 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -27,9 +27,7 @@ fn foo() {} static BAR: () = unsafe { *FOO.0.get() = 5; - // we do not error on the above access, because that is not detectable statically. Instead, - // const evaluation will error when trying to evaluate it. Due to the error below, we never even - // attempt to const evaluate `BAR`, so we don't see the error + //~^ contains unimplemented expression foo(); //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 01ad1fc9a21b9..49b39e2f5c6c9 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,9 +1,16 @@ +error[E0019]: static contains unimplemented expression type + --> $DIR/mod-static-with-const-fn.rs:29:5 + | +LL | *FOO.0.get() = 5; + | ^^^^^^^^^^^^^^^^ + error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:34:5 + --> $DIR/mod-static-with-const-fn.rs:32:5 | LL | foo(); | ^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors occurred: E0015, E0019. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 30a738a83a3b6..2f7e2ecaa4e40 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -37,15 +37,13 @@ const fn get_Y_addr() -> &'static u32 { } const fn get() -> u32 { - 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 + let x = 22; //~ ERROR let bindings in constant functions are unstable +//~^ ERROR statements in constant functions + let y = 44; //~ ERROR let bindings in constant functions are unstable +//~^ ERROR statements in constant functions x + y - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR let bindings in constant functions are unstable +//~^ ERROR let bindings in constant functions are unstable +//~| ERROR let bindings in constant functions are unstable } fn main() {} diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr index 613670acc9326..1a8c5f558a212 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr +++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr @@ -19,7 +19,7 @@ LL | &Y error[E0658]: let bindings in constant functions are unstable (see issue #48821) --> $DIR/const-fn-not-safe-for-const.rs:40:13 | -LL | let x = 22; +LL | let x = 22; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable @@ -27,29 +27,29 @@ LL | let x = 22; error[E0658]: statements in constant functions are unstable (see issue #48821) --> $DIR/const-fn-not-safe-for-const.rs:40:13 | -LL | let x = 22; +LL | let x = 22; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:43:13 + --> $DIR/const-fn-not-safe-for-const.rs:42:13 | -LL | let y = 44; +LL | let y = 44; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:43:13 + --> $DIR/const-fn-not-safe-for-const.rs:42:13 | -LL | let y = 44; +LL | let y = 44; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:46:5 + --> $DIR/const-fn-not-safe-for-const.rs:44:5 | LL | x + y | ^ @@ -57,7 +57,7 @@ LL | x + y = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:46:9 + --> $DIR/const-fn-not-safe-for-const.rs:44:9 | LL | x + y | ^ diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index 83825456b5c61..c2ed6cd85ab5c 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -8,6 +8,7 @@ struct S { impl S { const fn foo(&mut self, x: u32) { self.state = x; + //~^ contains unimplemented expression } } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 7f9a953c10fe8..0f294616d255c 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,9 +1,16 @@ +error[E0019]: constant function contains unimplemented expression type + --> $DIR/const_let_assign3.rs:10:9 + | +LL | self.state = x; + | ^^^^^^^^^^^^^^ + error[E0017]: references in constants may only refer to immutable values - --> $DIR/const_let_assign3.rs:16:5 + --> $DIR/const_let_assign3.rs:17:5 | LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values | ^ constants require immutable values -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0017`. +Some errors occurred: E0017, E0019. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/const_let_eq.rs b/src/test/ui/consts/const_let_eq.rs new file mode 100644 index 0000000000000..8739cb80e9403 --- /dev/null +++ b/src/test/ui/consts/const_let_eq.rs @@ -0,0 +1,470 @@ +#![feature(const_let, const_fn)] + +// run-pass + +struct Foo(T); +struct Bar { x: T } +struct W(u32); +struct A { a: u32 } + +const fn basics((a,): (u32,)) -> u32 { + // Deferred assignment: + let b: u32; + b = a + 1; + + // Immediate assignment: + let c: u32 = b + 1; + + // Mutables: + let mut d: u32 = c + 1; + d = d + 1; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] = 1; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo = Foo(0); + let mut bar: Bar = Bar { x: 0 }; + foo.0 = 1; + bar.x = 1; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(0)]; + arr[0].0 = 1; + d = d + arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 0 }]; + arr[0].x = 1; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] = 1; + d = d + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] = 1; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d += 1; + // +2 so far. + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] += 1; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo = Foo(0); + let mut bar: Bar = Bar { x: 0 }; + foo.0 += 1; + bar.x += 1; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(0)]; + arr[0].0 += 1; + d += arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 0 }]; + arr[0].x += 1; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] += 1; + d += (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] += 1; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d *= 2; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] *= 2; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo = Foo(1); + let mut bar: Bar = Bar { x: 1 }; + foo.0 *= 2; + bar.x *= 2; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(1)]; + arr[0].0 *= 2; + d *= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 1 }]; + arr[0].x *= 2; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] *= 2; + d *= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] *= 2; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [u32; 1]) -> u32 { + let a = a[0]; + // Mutables: + let mut d: u32 = 1024 * a; + d /= 2; + // 512 + + // Array projection + let mut arr: [u32; 1] = [4]; + arr[0] /= 2; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo = Foo(4); + let mut bar: Bar = Bar { x: 4 }; + foo.0 /= 2; + bar.x /= 2; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(4)]; + arr[0].0 /= 2; + d /= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 4 }]; + arr[0].x /= 2; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([4]); + (arr.0)[0] /= 2; + d /= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [4] }; + arr.x[0] /= 2; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d %= 10; + d += 10; + + // Array projection + let mut arr: [u32; 1] = [3]; + arr[0] %= 2; + d %= 9 + arr[0]; + d += 10; + + // Field projection: + let mut foo: Foo = Foo(5); + let mut bar: Bar = Bar { x: 7 }; + foo.0 %= 2; + bar.x %= 2; + d %= 8 + foo.0 + bar.x; + d += 10; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(4)]; + arr[0].0 %= 3; + d %= 9 + arr[0].0; + d += 10; + let mut arr: [Bar; 1] = [Bar { x: 7 }]; + arr[0].x %= 3; + d %= 9 + arr[0].x; + d += 10; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([6]); + (arr.0)[0] %= 5; + d %= 9 + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [11] }; + arr.x[0] %= 5; + d %= 9 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d -= 1; + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] -= 1; + d -= arr[0]; + + // Field projection: + let mut foo: Foo = Foo(2); + let mut bar: Bar = Bar { x: 2 }; + foo.0 -= 1; + bar.x -= 1; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(2)]; + arr[0].0 -= 1; + d -= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 2 }]; + arr[0].x -= 1; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] -= 1; + d -= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] -= 1; + d -= arr.x[0]; + + d +} + +const fn shl_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d <<= 1; // 10 + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] <<= 1; + d <<= arr[0]; // 10 << 2 + + // Field projection: + let mut foo: Foo = Foo(1); + let mut bar: Bar = Bar { x: 1 }; + foo.0 <<= 1; + bar.x <<= 1; + d <<= foo.0 + bar.x; // 1000 << 4 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(1)]; + arr[0].0 <<= 1; + d <<= arr[0].0; // 1000_0000 << 2 + let mut arr: [Bar; 1] = [Bar { x: 1 }]; + arr[0].x <<= 1; + d <<= arr[0].x; // 1000_0000_00 << 2 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] <<= 1; + d <<= (arr.0)[0]; // 1000_0000_0000 << 2 + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] <<= 1; + d <<= arr.x[0]; // 1000_0000_0000_00 << 2 + + d +} + +const fn shr_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d >>= 1; // /= 2 + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] >>= 1; + d >>= arr[0]; // /= 4 + + // Field projection: + let mut foo: Foo = Foo(2); + let mut bar: Bar = Bar { x: 2 }; + foo.0 >>= 1; + bar.x >>= 1; + d >>= foo.0 + bar.x; // /= 16 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(2)]; + arr[0].0 >>= 1; + d >>= arr[0].0; // /= 32 + let mut arr: [Bar; 1] = [Bar { x: 2 }]; + arr[0].x >>= 1; + d >>= arr[0].x; // /= 64 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] >>= 1; + d >>= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] >>= 1; + d >>= arr.x[0]; // /= 256 + + d +} + +const fn bit_and_assign(W(a): W) -> u32 { + let f = 0b1111_1111_1111_1111; + + // Mutables: + let mut d: u32 = a; + d &= 0b1111_1111_1111_1110; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] &= 0b1111_1111_1111_1101; + d &= arr[0]; + + // Field projection: + let mut foo: Foo = Foo(f); + let mut bar: Bar = Bar { x: f }; + foo.0 &= 0b1111_1111_1111_0111; + bar.x &= 0b1111_1111_1101_1111; + d &= foo.0 & bar.x; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(f)]; + arr[0].0 &= 0b1111_1110_1111_1111; + d &= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: f }]; + arr[0].x &= 0b1111_1101_1111_1111; + d &= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] &= 0b1011_1111_1111_1111; + d &= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] &= 0b0111_1111_1111_1111; + d &= arr.x[0]; + + d +} + +const fn bit_or_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d |= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] |= 0b0000_0000_0000_1001; + d |= arr[0]; + + // Field projection: + let mut foo: Foo = Foo(f); + let mut bar: Bar = Bar { x: f }; + foo.0 |= 0b0000_0000_0001_0000; + bar.x |= 0b0000_0000_0100_0000; + d |= foo.0 | bar.x; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(f)]; + arr[0].0 |= 0b0000_0001_0000_0000; + d |= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: f }]; + arr[0].x |= 0b0000_0010_0000_0000; + d |= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] |= 0b1000_0000_0000_0000; + d |= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] |= 0b1100_0000_0000_0000; + d |= arr.x[0]; // /= 256 + + d +} + +const fn bit_xor_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d ^= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] ^= 0b0000_0000_0000_0010; + d ^= arr[0]; + + // Field projection: + let mut foo: Foo = Foo(f); + let mut bar: Bar = Bar { x: f }; + foo.0 ^= 0b0000_0000_0001_0000; + bar.x ^= 0b0000_0000_1000_0000; + d ^= foo.0 ^ bar.x; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(f)]; + arr[0].0 ^= 0b0000_0001_0000_0000; + d ^= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: f }]; + arr[0].x ^= 0b0000_0010_0000_0000; + d ^= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] ^= 0b0100_0000_0000_0000; + d ^= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] ^= 0b1000_0000_0000_0000; + d ^= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: u32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2,)), 13); + test!(ADD, add_assign(W(1)), 10); + test!(MUL, mul_assign(A { a: 0 }), 256); + test!(DIV, div_assign([1]), 4); + test!(REM, rem_assign(W(5)), 5); + test!(SUB, sub_assign(W(8)), 0); + test!(SHL, shl_assign(W(1)), 0b1000_0000_0000_0000); + test!(SHR, shr_assign(W(256)), 1); + test!(AND, bit_and_assign(W(0b1011_1111_1111_1111_1111)), 0b0011_1100_1101_0100); + test!(OR, bit_or_assign(W(0b1011_0000_0000_0000)), 0b1111_0011_0101_1001); + test!(XOR, bit_xor_assign(W(0b0000_0000_0000_0000)), 0b1100_0011_1001_0011); +} diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs new file mode 100644 index 0000000000000..2c7262df367a3 --- /dev/null +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -0,0 +1,279 @@ +// compile-pass + +#![feature(const_let, const_fn)] + +struct Foo(T); +struct Bar { x: T } +struct W(f32); +struct A { a: f32 } + +const fn basics((a,): (f32,)) -> f32 { + // Deferred assignment: + let b: f32; + b = a + 1.0; + + // Immediate assignment: + let c: f32 = b + 1.0; + + // Mutables: + let mut d: f32 = c + 1.0; + d = d + 1.0; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] = 1.0; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo = Foo(0.0); + let mut bar: Bar = Bar { x: 0.0 }; + foo.0 = 1.0; + bar.x = 1.0; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(0.0)]; + arr[0].0 = 1.0; + d = d + arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 0.0 }]; + arr[0].x = 1.0; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] = 1.0; + d = d + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] = 1.0; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d += 1.0; + // +2 so far. + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] += 1.0; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo = Foo(0.0); + let mut bar: Bar = Bar { x: 0.0 }; + foo.0 += 1.0; + bar.x += 1.0; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(0.0)]; + arr[0].0 += 1.0; + d += arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 0.0 }]; + arr[0].x += 1.0; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] += 1.0; + d += (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] += 1.0; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d *= 2.0; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [f32; 1] = [1.0]; + arr[0] *= 2.0; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo = Foo(1.0); + let mut bar: Bar = Bar { x: 1.0 }; + foo.0 *= 2.0; + bar.x *= 2.0; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(1.0)]; + arr[0].0 *= 2.0; + d *= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 1.0 }]; + arr[0].x *= 2.0; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([1.0]); + (arr.0)[0] *= 2.0; + d *= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [1.0] }; + arr.x[0] *= 2.0; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [f32; 1]) -> f32 { + let a = a[0]; + // Mutables: + let mut d: f32 = 1024.0 * a; + d /= 2.0; + // 512 + + // Array projection + let mut arr: [f32; 1] = [4.0]; + arr[0] /= 2.0; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo = Foo(4.0); + let mut bar: Bar = Bar { x: 4.0 }; + foo.0 /= 2.0; + bar.x /= 2.0; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(4.0)]; + arr[0].0 /= 2.0; + d /= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 4.0 }]; + arr[0].x /= 2.0; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([4.0]); + (arr.0)[0] /= 2.0; + d /= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [4.0] }; + arr.x[0] /= 2.0; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d %= 10.0; + d += 10.0; + + // Array projection + let mut arr: [f32; 1] = [3.0]; + arr[0] %= 2.0; + d %= 9.0 + arr[0]; + d += 10.0; + + // Field projection: + let mut foo: Foo = Foo(5.0); + let mut bar: Bar = Bar { x: 7.0 }; + foo.0 %= 2.0; + bar.x %= 2.0; + d %= 8.0 + foo.0 + bar.x; + d += 10.0; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(4.0)]; + arr[0].0 %= 3.0; + d %= 9.0 + arr[0].0; + d += 10.0; + let mut arr: [Bar; 1] = [Bar { x: 7.0 }]; + arr[0].x %= 3.0; + d %= 9.0 + arr[0].x; + d += 10.0; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([6.0]); + (arr.0)[0] %= 5.0; + d %= 9.0 + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [11.0] }; + arr.x[0] %= 5.0; + d %= 9.0 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d -= 1.0; + + // Array projection + let mut arr: [f32; 1] = [2.0]; + arr[0] -= 1.0; + d -= arr[0]; + + // Field projection: + let mut foo: Foo = Foo(2.0); + let mut bar: Bar = Bar { x: 2.0 }; + foo.0 -= 1.0; + bar.x -= 1.0; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo; 1] = [Foo(2.0)]; + arr[0].0 -= 1.0; + d -= arr[0].0; + let mut arr: [Bar; 1] = [Bar { x: 2.0 }]; + arr[0].x -= 1.0; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([2.0]); + (arr.0)[0] -= 1.0; + d -= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [2.0] }; + arr.x[0] -= 1.0; + d -= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: f32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2.0,)), 13.0); + test!(ADD, add_assign(W(1.0)), 10.0); + test!(MUL, mul_assign(A { a: 0.0 }), 256.0); + test!(DIV, div_assign([1.0]), 4.0); + test!(REM, rem_assign(W(5.0)), 5.0); + test!(SUB, sub_assign(W(8.0)), 0.0); +} diff --git a/src/test/ui/consts/const_short_circuit.rs b/src/test/ui/consts/const_short_circuit.rs new file mode 100644 index 0000000000000..cc49e4696e58f --- /dev/null +++ b/src/test/ui/consts/const_short_circuit.rs @@ -0,0 +1,16 @@ +#![feature(underscore_const_names, const_let)] + +const _: bool = false && false; +const _: bool = true && false; +const _: bool = { + let mut x = true && false; + //~^ ERROR new features like let bindings are not permitted + x +}; +const _: bool = { + let x = true && false; + //~^ ERROR new features like let bindings are not permitted + x +}; + +fn main() {} diff --git a/src/test/ui/consts/const_short_circuit.stderr b/src/test/ui/consts/const_short_circuit.stderr new file mode 100644 index 0000000000000..a67bb0b1b6d98 --- /dev/null +++ b/src/test/ui/consts/const_short_circuit.stderr @@ -0,0 +1,26 @@ +error: new features like let bindings are not permitted in constants which also use short circuiting operators + --> $DIR/const_short_circuit.rs:6:9 + | +LL | let mut x = true && false; + | ^^^^^ + | +note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. + --> $DIR/const_short_circuit.rs:6:22 + | +LL | let mut x = true && false; + | ^^ + +error: new features like let bindings are not permitted in constants which also use short circuiting operators + --> $DIR/const_short_circuit.rs:11:9 + | +LL | let x = true && false; + | ^ + | +note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. + --> $DIR/const_short_circuit.rs:11:18 + | +LL | let x = true && false; + | ^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr index f43befb37c134..6c4e9e0a067d7 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn error: local variables in const fn are unstable --> $DIR/min_const_fn.rs:109:34 | -LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn | ^ error: `if`, `match`, `&&` and `||` are not stable in const fn diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 0dba3a7de5378..ba6989f8b417a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -106,7 +106,7 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize } const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } //~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn -const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn const fn foo36(a: bool, b: bool) -> bool { a && b } //~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn const fn foo37(a: bool, b: bool) -> bool { a || b } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index bcb9be6e5485e..a93a4f817fc14 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn error: local variables in const fn are unstable --> $DIR/min_const_fn.rs:109:34 | -LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn | ^ error: `if`, `match`, `&&` and `||` are not stable in const fn diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.rs b/src/test/ui/consts/min_const_fn/mutable_borrow.rs new file mode 100644 index 0000000000000..3dd76b630a883 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.rs @@ -0,0 +1,17 @@ +const fn mutable_ref_in_const() -> u8 { + let mut a = 0; //~ ERROR local variables in const fn + let b = &mut a; + *b +} + +struct X; + +impl X { + const fn inherent_mutable_ref_in_const() -> u8 { + let mut a = 0; //~ ERROR local variables in const fn + let b = &mut a; + *b + } +} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr new file mode 100644 index 0000000000000..fa46f5c804fe0 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -0,0 +1,14 @@ +error: local variables in const fn are unstable + --> $DIR/mutable_borrow.rs:2:9 + | +LL | let mut a = 0; //~ ERROR local variables in const fn + | ^^^^^ + +error: local variables in const fn are unstable + --> $DIR/mutable_borrow.rs:11:13 + | +LL | let mut a = 0; //~ ERROR local variables in const fn + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index 34e8eaba9f28f..5863429a2f2c5 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -7,6 +7,7 @@ const FOO: &u32 = { { let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + //~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr index d5252f199beac..cc3635a979b37 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values | ^^^^^^ constants require immutable values +error[E0019]: constant contains unimplemented expression type + --> $DIR/projection_qualif.rs:9:18 + | +LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + | ^^^^^^ + error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) --> $DIR/projection_qualif.rs:9:18 | @@ -12,7 +18,7 @@ LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constant | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0017, E0658. +Some errors occurred: E0017, E0019, E0658. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs index 67a41bc5dc4ad..79dde3c18e8fa 100644 --- a/src/test/ui/consts/single_variant_match_ice.rs +++ b/src/test/ui/consts/single_variant_match_ice.rs @@ -2,6 +2,14 @@ enum Foo { Prob, } +const FOO: u32 = match Foo::Prob { + Foo::Prob => 42, //~ ERROR unimplemented expression type +}; + +const BAR: u32 = match Foo::Prob { + x => 42, //~ ERROR unimplemented expression type +}; + impl Foo { pub const fn as_val(&self) -> u8 { use self::Foo::*; diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr index a0222b0d489a4..f5c2cb5e0e9dc 100644 --- a/src/test/ui/consts/single_variant_match_ice.stderr +++ b/src/test/ui/consts/single_variant_match_ice.stderr @@ -1,8 +1,21 @@ +error[E0019]: constant contains unimplemented expression type + --> $DIR/single_variant_match_ice.rs:6:5 + | +LL | Foo::Prob => 42, //~ ERROR unimplemented expression type + | ^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/single_variant_match_ice.rs:10:5 + | +LL | x => 42, //~ ERROR unimplemented expression type + | ^ + error: `if`, `match`, `&&` and `||` are not stable in const fn - --> $DIR/single_variant_match_ice.rs:10:13 + --> $DIR/single_variant_match_ice.rs:18:13 | LL | Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn | ^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/feature-gates/feature-gate-const_let.rs b/src/test/ui/feature-gates/feature-gate-const_let.rs index 05d02e62bc871..9bf957a5f1e05 100644 --- a/src/test/ui/feature-gates/feature-gate-const_let.rs +++ b/src/test/ui/feature-gates/feature-gate-const_let.rs @@ -10,13 +10,22 @@ // Test use of const let without feature gate. -#![feature(const_fn)] +const FOO: usize = { + //~^ ERROR statements in constants are unstable + //~| ERROR: let bindings in constants are unstable + let x = 42; + //~^ ERROR statements in constants are unstable + //~| ERROR: let bindings in constants are unstable + 42 +}; -const fn foo() -> usize { +static BAR: usize = { + //~^ ERROR statements in statics are unstable + //~| ERROR: let bindings in statics are unstable let x = 42; - //~^ ERROR statements in constant functions are unstable - //~| ERROR: let bindings in constant functions are unstable + //~^ ERROR statements in statics are unstable + //~| ERROR: let bindings in statics are unstable 42 -} +}; fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_let.stderr b/src/test/ui/feature-gates/feature-gate-const_let.stderr index 6a7f6255678ff..acb5165918e2a 100644 --- a/src/test/ui/feature-gates/feature-gate-const_let.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_let.stderr @@ -1,4 +1,4 @@ -error[E0658]: let bindings in constant functions are unstable (see issue #48821) +error[E0658]: let bindings in constants are unstable (see issue #48821) --> $DIR/feature-gate-const_let.rs:16:13 | LL | let x = 42; @@ -6,7 +6,7 @@ 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) +error[E0658]: statements in constants are unstable (see issue #48821) --> $DIR/feature-gate-const_let.rs:16:13 | LL | let x = 42; @@ -14,6 +14,78 @@ LL | let x = 42; | = help: add #![feature(const_let)] to the crate attributes to enable -error: aborting due to 2 previous errors +error[E0658]: let bindings in constants are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:13:1 + | +LL | / const FOO: usize = { +LL | | //~^ ERROR statements in constants are unstable +LL | | //~| ERROR: let bindings in constants are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in constants are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:13:1 + | +LL | / const FOO: usize = { +LL | | //~^ ERROR statements in constants are unstable +LL | | //~| ERROR: let bindings in constants are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: let bindings in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:25:13 + | +LL | let x = 42; + | ^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:25:13 + | +LL | let x = 42; + | ^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: let bindings in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:22:1 + | +LL | / static BAR: usize = { +LL | | //~^ ERROR statements in statics are unstable +LL | | //~| ERROR: let bindings in statics are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:22:1 + | +LL | / static BAR: usize = { +LL | | //~^ ERROR statements in statics are unstable +LL | | //~| ERROR: let bindings in statics are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs index af1f6ef5ed4ac..a2f40b3f5396c 100644 --- a/src/test/ui/issues/issue-37550.rs +++ b/src/test/ui/issues/issue-37550.rs @@ -8,15 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] - const fn x() { - let t = true; - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR statements in constant functions are unstable + let t = true; //~ ERROR local variables in const fn 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/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr index 7468510de6a33..5a7d1ad043ee4 100644 --- a/src/test/ui/issues/issue-37550.stderr +++ b/src/test/ui/issues/issue-37550.stderr @@ -1,35 +1,8 @@ -error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:14:13 +error: local variables in const fn are unstable + --> $DIR/issue-37550.rs:12:9 | -LL | let t = true; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:14:13 - | -LL | let t = true; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:17:13 - | -LL | let x = || t; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:17:13 - | -LL | let x = || t; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable +LL | let t = true; //~ ERROR local variables in const fn + | ^ -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`.