From 365d1236890469cff1a55a28eeb9befaf516d552 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 10:27:31 -0700 Subject: [PATCH 01/10] Add feature gate for const `if` and `match` --- src/librustc_mir/transform/check_consts/ops.rs | 4 ++++ src/librustc_mir/transform/qualify_min_const_fn.rs | 13 +++++++++++-- src/librustc_passes/check_const.rs | 2 +- src/libsyntax/feature_gate/active.rs | 3 +++ src/libsyntax_pos/symbol.rs | 1 + 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 80f2925193a81..950f48f03cd97 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -139,6 +139,10 @@ impl NonConstOp for HeapAllocation { #[derive(Debug)] pub struct IfOrMatch; impl NonConstOp for IfOrMatch { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_if_match) + } + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { // This should be caught by the HIR const-checker. item.tcx.sess.delay_span_bug( diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 83bde5ed34eae..cb6f94adbf08c 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -216,7 +216,9 @@ fn check_statement( check_rvalue(tcx, body, def_id, rval, span) } - StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => { + | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) + if !tcx.features().const_if_match + => { Err((span, "loops and conditional expressions are not stable in const fn".into())) } @@ -324,10 +326,17 @@ fn check_terminator( check_operand(tcx, value, span, def_id, body) }, - TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err(( + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::SwitchInt { .. } + if !tcx.features().const_if_match + => Err(( span, "loops and conditional expressions are not stable in const fn".into(), )), + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::SwitchInt { .. } + => Ok(()), + | TerminatorKind::Abort | TerminatorKind::Unreachable => { Err((span, "const fn with unreachable code is not stable".into())) } diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 9d37b4bdb769c..9870a78bd4472 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -135,7 +135,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.const_check_violated(source.name(), e.span); } - hir::ExprKind::Match(_, _, source) => { + hir::ExprKind::Match(_, _, source) if !self.tcx.features().const_if_match => { use hir::MatchSource::*; let op = match source { diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index bd029514a9524..fa0ab90c702b9 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -529,6 +529,9 @@ declare_features! ( /// Allows using the `#[register_attr]` attribute. (active, register_tool, "1.41.0", Some(66079), None), + /// Allows the use of `if` and `match` in constants. + (active, const_if_match, "1.41.0", Some(49146), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 979074f17c7e0..e7238caca8e4b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -202,6 +202,7 @@ symbols! { const_fn, const_fn_union, const_generics, + const_if_match, const_indexing, const_in_array_repeat_expressions, const_let, From e969fb2176afa6b82f44256b62c777193b972742 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 19 Sep 2019 11:25:19 -0700 Subject: [PATCH 02/10] Don't transform short-circuiting logic if `const_if_match` enabled --- src/librustc_mir/hair/cx/expr.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index f25e4b0ae8639..12b3108c5f2de 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -341,9 +341,10 @@ fn make_mirror_unadjusted<'a, 'tcx>( } else { // FIXME overflow match (op.node, cx.constness) { - // FIXME(eddyb) use logical ops in constants when - // they can handle that kind of control-flow. - (hir::BinOpKind::And, hir::Constness::Const) => { + // Destroy control flow if `#![feature(const_if_match)]` is not enabled. + (hir::BinOpKind::And, hir::Constness::Const) + if !cx.tcx.features().const_if_match => + { cx.control_flow_destroyed.push(( op.span, "`&&` operator".into(), @@ -354,7 +355,9 @@ fn make_mirror_unadjusted<'a, 'tcx>( rhs: rhs.to_ref(), } } - (hir::BinOpKind::Or, hir::Constness::Const) => { + (hir::BinOpKind::Or, hir::Constness::Const) + if !cx.tcx.features().const_if_match => + { cx.control_flow_destroyed.push(( op.span, "`||` operator".into(), @@ -366,14 +369,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } - (hir::BinOpKind::And, hir::Constness::NotConst) => { + (hir::BinOpKind::And, _) => { ExprKind::LogicalOp { op: LogicalOp::And, lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } - (hir::BinOpKind::Or, hir::Constness::NotConst) => { + (hir::BinOpKind::Or, _) => { ExprKind::LogicalOp { op: LogicalOp::Or, lhs: lhs.to_ref(), From a98d20a260883739f5c31d67fc0d5918863742d1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 17 Nov 2019 20:41:34 -0800 Subject: [PATCH 03/10] Allow `Downcast` projections if `const_if_match` enabled These are generated when matching on enum variants to extract the value within. We should have no problem evaluating these, but care should be taken that we aren't accidentally allowing some other operation. --- src/librustc_mir/transform/check_consts/ops.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 950f48f03cd97..acad56be60403 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -52,7 +52,11 @@ pub trait NonConstOp: std::fmt::Debug { /// A `Downcast` projection. #[derive(Debug)] pub struct Downcast; -impl NonConstOp for Downcast {} +impl NonConstOp for Downcast { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_if_match) + } +} /// A function call where the callee is a pointer. #[derive(Debug)] From 929ff68376e62b10f71df27481b97c42bb7a69d5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 Nov 2019 14:46:11 -0800 Subject: [PATCH 04/10] Hold a `TyCtxt` in the HIR const-checker --- src/librustc_passes/check_const.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 9870a78bd4472..b90959518c23d 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -11,7 +11,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::map::Map; use rustc::hir; -use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use syntax::ast::Mutability; @@ -75,31 +74,29 @@ pub(crate) fn provide(providers: &mut Providers<'_>) { #[derive(Copy, Clone)] struct CheckConstVisitor<'tcx> { - sess: &'tcx Session, - hir_map: &'tcx Map<'tcx>, + tcx: TyCtxt<'tcx>, const_kind: Option, } impl<'tcx> CheckConstVisitor<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { CheckConstVisitor { - sess: &tcx.sess, - hir_map: tcx.hir(), + tcx, const_kind: None, } } /// Emits an error when an unsupported expression is found in a const context. fn const_check_violated(&self, bad_op: &str, span: Span) { - if self.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - self.sess.span_warn(span, "skipping const checks"); + if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + self.tcx.sess.span_warn(span, "skipping const checks"); return; } let const_kind = self.const_kind .expect("`const_check_violated` may only be called inside a const context"); - span_err!(self.sess, span, E0744, "`{}` is not allowed in a `{}`", bad_op, const_kind); + span_err!(self.tcx.sess, span, E0744, "`{}` is not allowed in a `{}`", bad_op, const_kind); } /// Saves the parent `const_kind` before calling `f` and restores it afterwards. @@ -113,7 +110,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.hir_map) + NestedVisitorMap::OnlyBodies(&self.tcx.hir()) } fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { @@ -122,7 +119,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { } fn visit_body(&mut self, body: &'tcx hir::Body) { - let kind = ConstKind::for_body(body, self.hir_map); + let kind = ConstKind::for_body(body, self.tcx.hir()); self.recurse_into(kind, |this| hir::intravisit::walk_body(this, body)); } From f4b9dc7d59ca4ebcf4841a80e83feb8fcaf353cc Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 18 Nov 2019 12:58:28 -0800 Subject: [PATCH 05/10] Make `name` work for `MatchSource` --- src/librustc/hir/mod.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 17b13dae37fdb..6f34b42d91c1f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1749,6 +1749,20 @@ pub enum MatchSource { AwaitDesugar, } +impl MatchSource { + pub fn name(self) -> &'static str { + use MatchSource::*; + match self { + Normal => "match", + IfDesugar { .. } | IfLetDesugar { .. } => "if", + WhileDesugar | WhileLetDesugar => "while", + ForLoopDesugar => "for", + TryDesugar => "?", + AwaitDesugar => ".await", + } + } +} + /// The loop type that yielded an `ExprKind::Loop`. #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum LoopSource { @@ -1766,8 +1780,7 @@ impl LoopSource { pub fn name(self) -> &'static str { match self { LoopSource::Loop => "loop", - LoopSource::While => "while", - LoopSource::WhileLet => "while let", + LoopSource::While | LoopSource::WhileLet => "while", LoopSource::ForLoop => "for", } } From ccb6e9884ed869ce881248b8662291121310b67d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 Nov 2019 23:08:30 -0800 Subject: [PATCH 06/10] Suggest `const_if_match` on nightly --- src/librustc_passes/check_const.rs | 89 +++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 19 deletions(-) diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index b90959518c23d..24bc088e24a70 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -14,12 +14,43 @@ use rustc::hir; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use syntax::ast::Mutability; +use syntax::feature_gate::{emit_feature_err, Features, GateIssue}; use syntax::span_err; -use syntax_pos::Span; +use syntax_pos::{sym, Span}; use rustc_error_codes::*; use std::fmt; +/// An expression that is not *always* legal in a const context. +#[derive(Clone, Copy)] +enum NonConstExpr { + Loop(hir::LoopSource), + Match(hir::MatchSource), +} + +impl NonConstExpr { + fn name(self) -> &'static str { + match self { + Self::Loop(src) => src.name(), + Self::Match(src) => src.name(), + } + } + + /// Returns `true` if all feature gates required to enable this expression are turned on, or + /// `None` if there is no feature gate corresponding to this expression. + fn is_feature_gate_enabled(self, features: &Features) -> Option { + use hir::MatchSource::*; + match self { + | Self::Match(Normal) + | Self::Match(IfDesugar { .. }) + | Self::Match(IfLetDesugar { .. }) + => Some(features.const_if_match), + + _ => None, + } + } +} + #[derive(Copy, Clone)] enum ConstKind { Static, @@ -87,16 +118,38 @@ impl<'tcx> CheckConstVisitor<'tcx> { } /// Emits an error when an unsupported expression is found in a const context. - fn const_check_violated(&self, bad_op: &str, span: Span) { - if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - self.tcx.sess.span_warn(span, "skipping const checks"); - return; + fn const_check_violated(&self, expr: NonConstExpr, span: Span) { + match expr.is_feature_gate_enabled(self.tcx.features()) { + // Don't emit an error if the user has enabled the requisite feature gates. + Some(true) => return, + + // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible. + None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => { + self.tcx.sess.span_warn(span, "skipping const checks"); + return; + } + + _ => {} } let const_kind = self.const_kind .expect("`const_check_violated` may only be called inside a const context"); - span_err!(self.tcx.sess, span, E0744, "`{}` is not allowed in a `{}`", bad_op, const_kind); + let msg = format!("`{}` is not allowed in a `{}`", expr.name(), const_kind); + match expr { + | NonConstExpr::Match(hir::MatchSource::Normal) + | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. }) + | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. }) + => emit_feature_err( + &self.tcx.sess.parse_sess, + sym::const_if_match, + span, + GateIssue::Language, + &msg + ), + + _ => span_err!(self.tcx.sess, span, E0744, "{}", msg), + } } /// Saves the parent `const_kind` before calling `f` and restores it afterwards. @@ -129,24 +182,22 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { _ if self.const_kind.is_none() => {} hir::ExprKind::Loop(_, _, source) => { - self.const_check_violated(source.name(), e.span); + self.const_check_violated(NonConstExpr::Loop(*source), e.span); } - hir::ExprKind::Match(_, _, source) if !self.tcx.features().const_if_match => { - use hir::MatchSource::*; - - let op = match source { - Normal => Some("match"), - IfDesugar { .. } | IfLetDesugar { .. } => Some("if"), - TryDesugar => Some("?"), - AwaitDesugar => Some(".await"), - + hir::ExprKind::Match(_, _, source) => { + let non_const_expr = match source { // These are handled by `ExprKind::Loop` above. - WhileDesugar | WhileLetDesugar | ForLoopDesugar => None, + | hir::MatchSource::WhileDesugar + | hir::MatchSource::WhileLetDesugar + | hir::MatchSource::ForLoopDesugar + => None, + + _ => Some(NonConstExpr::Match(*source)), }; - if let Some(op) = op { - self.const_check_violated(op, e.span); + if let Some(expr) = non_const_expr { + self.const_check_violated(expr, e.span); } } From 26d93f35f6965cec7e75099bc775e24c61ca9f7a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 Nov 2019 22:55:45 -0800 Subject: [PATCH 07/10] Add entry for `const_if_match` in unstable book --- .../src/language-features/const-if-match.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/const-if-match.md diff --git a/src/doc/unstable-book/src/language-features/const-if-match.md b/src/doc/unstable-book/src/language-features/const-if-match.md new file mode 100644 index 0000000000000..ee9cfcbd9dee2 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/const-if-match.md @@ -0,0 +1,14 @@ +# `const_if_match` + +The tracking issue for this feature is: [#49146] + +[#49146]: https://github.com/rust-lang/rust/issues/49146 + +------------------------ + +Allows for the use of conditionals (`if` and `match`) in a const context. +Const contexts include `static`, `static mut`, `const`, `const fn`, const +generics, and array initializers. Enabling this feature flag will also make +`&&` and `||` function normally in a const-context by removing the hack that +replaces them with their non-short-circuiting equivalents, `&` and `|`, in a +`const` or `static`. From 5c377f37e4281d87b26c33dfdabf2ec1450e5095 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 17 Nov 2019 21:11:42 -0800 Subject: [PATCH 08/10] Reorganize, bless and add tests for const control flow This creates a new test directory, `ui/consts/control-flow` to hold tests related to control flow in a const context. It also blesses all existing tests with the new error messages, and adds new tests for the `const_if_match` feature. --- src/test/ui/borrowck/issue-64453.stderr | 6 +- .../ui/consts/const-eval/infinite_loop.stderr | 7 +- .../const-eval/match-test-ptr-null.stderr | 7 +- src/test/ui/consts/const-if.rs | 21 -- src/test/ui/consts/const-if.stderr | 37 --- src/test/ui/consts/const-loop.rs | 90 ------- .../ui/consts/const-match-pattern-arm.stderr | 12 +- .../ui/consts/control-flow/assert.both.stderr | 13 + .../control-flow/assert.if_match.stderr | 23 ++ .../consts/control-flow/assert.panic.stderr | 21 ++ src/test/ui/consts/control-flow/assert.rs | 17 ++ .../consts/control-flow/assert.stock.stderr | 21 ++ src/test/ui/consts/control-flow/basics.rs | 43 +++ .../ui/consts/control-flow/drop-failure.rs | 35 +++ .../consts/control-flow/drop-failure.stderr | 21 ++ .../ui/consts/control-flow/drop-success.rs | 24 ++ ...eature-gate-const-if-match.if_match.stderr | 14 + .../feature-gate-const-if-match.rs | 118 +++++++++ .../feature-gate-const-if-match.stock.stderr | 249 ++++++++++++++++++ .../control-flow/interior-mutability.rs | 27 ++ .../control-flow/interior-mutability.stderr | 24 ++ .../control-flow/issue-46843.if_match.stderr | 9 + .../ui/consts/control-flow/issue-46843.rs | 18 ++ .../control-flow/issue-46843.stock.stderr | 18 ++ .../control-flow/issue-50577.if_match.stderr | 16 ++ .../ui/consts/control-flow/issue-50577.rs | 13 + .../control-flow/issue-50577.stock.stderr} | 22 +- .../loop.if_match.stderr} | 52 ++-- src/test/ui/consts/control-flow/loop.rs | 97 +++++++ .../ui/consts/control-flow/loop.stock.stderr | 134 ++++++++++ .../consts/control-flow/short-circuit-let.rs | 39 +++ .../short-circuit.if_match.stderr | 8 + .../ui/consts/control-flow/short-circuit.rs | 14 + .../control-flow/short-circuit.stock.stderr | 23 ++ .../control-flow/single_variant_match_ice.rs | 27 ++ src/test/ui/consts/control-flow/try.rs | 12 + src/test/ui/consts/control-flow/try.stderr | 9 + .../ui/consts/single_variant_match_ice.rs | 23 -- .../ui/consts/single_variant_match_ice.stderr | 29 -- .../niche.rs} | 3 +- src/test/ui/issues/issue-46843.rs | 13 - src/test/ui/issues/issue-46843.stderr | 14 - src/test/ui/issues/issue-50577.rs | 9 - src/test/ui/issues/issue-51714.rs | 2 +- src/test/ui/issues/issue-51714.stderr | 2 +- src/test/ui/loops/loop-break-value.rs | 6 +- src/test/ui/loops/loop-break-value.stderr | 12 +- .../ui/return/return-match-array-const.stderr | 17 +- .../disallowed-positions.stderr | 17 +- 49 files changed, 1180 insertions(+), 308 deletions(-) delete mode 100644 src/test/ui/consts/const-if.rs delete mode 100644 src/test/ui/consts/const-if.stderr delete mode 100644 src/test/ui/consts/const-loop.rs create mode 100644 src/test/ui/consts/control-flow/assert.both.stderr create mode 100644 src/test/ui/consts/control-flow/assert.if_match.stderr create mode 100644 src/test/ui/consts/control-flow/assert.panic.stderr create mode 100644 src/test/ui/consts/control-flow/assert.rs create mode 100644 src/test/ui/consts/control-flow/assert.stock.stderr create mode 100644 src/test/ui/consts/control-flow/basics.rs create mode 100644 src/test/ui/consts/control-flow/drop-failure.rs create mode 100644 src/test/ui/consts/control-flow/drop-failure.stderr create mode 100644 src/test/ui/consts/control-flow/drop-success.rs create mode 100644 src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr create mode 100644 src/test/ui/consts/control-flow/feature-gate-const-if-match.rs create mode 100644 src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr create mode 100644 src/test/ui/consts/control-flow/interior-mutability.rs create mode 100644 src/test/ui/consts/control-flow/interior-mutability.stderr create mode 100644 src/test/ui/consts/control-flow/issue-46843.if_match.stderr create mode 100644 src/test/ui/consts/control-flow/issue-46843.rs create mode 100644 src/test/ui/consts/control-flow/issue-46843.stock.stderr create mode 100644 src/test/ui/consts/control-flow/issue-50577.if_match.stderr create mode 100644 src/test/ui/consts/control-flow/issue-50577.rs rename src/test/ui/{issues/issue-50577.stderr => consts/control-flow/issue-50577.stock.stderr} (61%) rename src/test/ui/consts/{const-loop.stderr => control-flow/loop.if_match.stderr} (67%) create mode 100644 src/test/ui/consts/control-flow/loop.rs create mode 100644 src/test/ui/consts/control-flow/loop.stock.stderr create mode 100644 src/test/ui/consts/control-flow/short-circuit-let.rs create mode 100644 src/test/ui/consts/control-flow/short-circuit.if_match.stderr create mode 100644 src/test/ui/consts/control-flow/short-circuit.rs create mode 100644 src/test/ui/consts/control-flow/short-circuit.stock.stderr create mode 100644 src/test/ui/consts/control-flow/single_variant_match_ice.rs create mode 100644 src/test/ui/consts/control-flow/try.rs create mode 100644 src/test/ui/consts/control-flow/try.stderr delete mode 100644 src/test/ui/consts/single_variant_match_ice.rs delete mode 100644 src/test/ui/consts/single_variant_match_ice.stderr rename src/test/ui/{consts/miri_unleashed/enum_discriminants.rs => enum-discriminant/niche.rs} (96%) delete mode 100644 src/test/ui/issues/issue-46843.rs delete mode 100644 src/test/ui/issues/issue-46843.stderr delete mode 100644 src/test/ui/issues/issue-50577.rs diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index f437880a1655f..0b66426aa2a0f 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,11 +1,13 @@ -error[E0744]: `match` is not allowed in a `static` +error[E0658]: `match` is not allowed in a `static` --> $DIR/issue-64453.rs:4:31 | LL | static settings_dir: String = format!(""); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0744`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index 2af6af95c5565..de2624d7f7acf 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -9,11 +9,14 @@ LL | | LL | | } | |_________^ -error[E0744]: `if` is not allowed in a `const` +error[E0658]: `if` is not allowed in a `const` --> $DIR/infinite_loop.rs:9:17 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable warning: Constant evaluating a complex constant, this might take some time --> $DIR/infinite_loop.rs:4:18 @@ -36,5 +39,5 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0080, E0744. +Some errors have detailed explanations: E0080, E0658, E0744. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index 587dca4c1f279..d1ad2261dc259 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -1,4 +1,4 @@ -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/match-test-ptr-null.rs:6:9 | LL | / match &1 as *const i32 as usize { @@ -9,6 +9,9 @@ LL | | 0 => 42, LL | | n => n, LL | | } | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constants is unstable --> $DIR/match-test-ptr-null.rs:6:15 @@ -27,5 +30,5 @@ LL | match &1 as *const i32 as usize { error: aborting due to 3 previous errors -Some errors have detailed explanations: E0080, E0658, E0744. +Some errors have detailed explanations: E0080, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-if.rs b/src/test/ui/consts/const-if.rs deleted file mode 100644 index 94cce60453dcc..0000000000000 --- a/src/test/ui/consts/const-if.rs +++ /dev/null @@ -1,21 +0,0 @@ -const _: i32 = if true { //~ ERROR `if` is not allowed in a `const` - 5 -} else { - 6 -}; - -const _: i32 = match 1 { //~ ERROR `match` is not allowed in a `const` - 2 => 3, - 4 => 5, - _ => 0, -}; - -const fn foo() -> i32 { - if true { 5 } else { 6 } //~ ERROR `if` is not allowed in a `const fn` -} - -const fn bar() -> i32 { - match 0 { 1 => 2, _ => 0 } //~ ERROR `match` is not allowed in a `const fn` -} - -fn main() {} diff --git a/src/test/ui/consts/const-if.stderr b/src/test/ui/consts/const-if.stderr deleted file mode 100644 index 6fb2a0e150190..0000000000000 --- a/src/test/ui/consts/const-if.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0744]: `if` is not allowed in a `const` - --> $DIR/const-if.rs:1:16 - | -LL | const _: i32 = if true { - | ________________^ -LL | | 5 -LL | | } else { -LL | | 6 -LL | | }; - | |_^ - -error[E0744]: `match` is not allowed in a `const` - --> $DIR/const-if.rs:7:16 - | -LL | const _: i32 = match 1 { - | ________________^ -LL | | 2 => 3, -LL | | 4 => 5, -LL | | _ => 0, -LL | | }; - | |_^ - -error[E0744]: `if` is not allowed in a `const fn` - --> $DIR/const-if.rs:14:5 - | -LL | if true { 5 } else { 6 } - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0744]: `match` is not allowed in a `const fn` - --> $DIR/const-if.rs:18:5 - | -LL | match 0 { 1 => 2, _ => 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/consts/const-loop.rs b/src/test/ui/consts/const-loop.rs deleted file mode 100644 index b0fe5e320f4a6..0000000000000 --- a/src/test/ui/consts/const-loop.rs +++ /dev/null @@ -1,90 +0,0 @@ -const _: () = loop {}; //~ ERROR `loop` is not allowed in a `const` - -static FOO: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `static` - -const fn foo() { - loop {} //~ ERROR `loop` is not allowed in a `const fn` -} - -pub trait Foo { - const BAR: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `const` -} - -impl Foo for () { - const BAR: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `const` -} - -fn non_const_outside() { - const fn const_inside() { - loop {} //~ ERROR `loop` is not allowed in a `const fn` - } -} - -const fn const_outside() { - fn non_const_inside() { - loop {} - } -} - -fn main() { - let x = [0; { - while false {} - //~^ ERROR `while` is not allowed in a `const` - 4 - }]; -} - -const _: i32 = { - let mut x = 0; - - while x < 4 { //~ ERROR `while` is not allowed in a `const` - x += 1; - } - - while x < 8 { //~ ERROR `while` is not allowed in a `const` - x += 1; - } - - x -}; - -const _: i32 = { - let mut x = 0; - - for i in 0..4 { //~ ERROR `for` is not allowed in a `const` - x += i; - } - - for i in 0..4 { //~ ERROR `for` is not allowed in a `const` - x += i; - } - - x -}; - -const _: i32 = { - let mut x = 0; - - loop { //~ ERROR `loop` is not allowed in a `const` - x += 1; - if x == 4 { //~ ERROR `if` is not allowed in a `const` - break; - } - } - - loop { //~ ERROR `loop` is not allowed in a `const` - x += 1; - if x == 8 { //~ ERROR `if` is not allowed in a `const` - break; - } - } - - x -}; - -const _: i32 = { - let mut x = 0; - while let None = Some(x) { } //~ ERROR `while let` is not allowed in a `const` - while let None = Some(x) { } //~ ERROR `while let` is not allowed in a `const` - x -}; diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr index 57ef349a377fd..4e7713f1422eb 100644 --- a/src/test/ui/consts/const-match-pattern-arm.stderr +++ b/src/test/ui/consts/const-match-pattern-arm.stderr @@ -1,4 +1,4 @@ -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/const-match-pattern-arm.rs:3:17 | LL | const x: bool = match Some(true) { @@ -7,8 +7,11 @@ LL | | Some(value) => true, LL | | _ => false LL | | }; | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/const-match-pattern-arm.rs:9:5 | LL | / match Some(true) { @@ -16,7 +19,10 @@ LL | | Some(value) => true, LL | | _ => false LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0744`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/assert.both.stderr b/src/test/ui/consts/control-flow/assert.both.stderr new file mode 100644 index 0000000000000..44769175f0ee9 --- /dev/null +++ b/src/test/ui/consts/control-flow/assert.both.stderr @@ -0,0 +1,13 @@ +error: any use of this value will cause an error + --> $DIR/assert.rs:12:15 + | +LL | const _: () = assert!(false); + | --------------^^^^^^^^^^^^^^- + | | + | the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:12:15 + | + = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/consts/control-flow/assert.if_match.stderr b/src/test/ui/consts/control-flow/assert.if_match.stderr new file mode 100644 index 0000000000000..9c8963f6c7b28 --- /dev/null +++ b/src/test/ui/consts/control-flow/assert.if_match.stderr @@ -0,0 +1,23 @@ +error[E0658]: panicking in constants is unstable + --> $DIR/assert.rs:8:15 + | +LL | const _: () = assert!(true); + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 + = help: add `#![feature(const_panic)]` to the crate attributes to enable + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0658]: panicking in constants is unstable + --> $DIR/assert.rs:12:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 + = help: add `#![feature(const_panic)]` to the crate attributes to enable + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/assert.panic.stderr b/src/test/ui/consts/control-flow/assert.panic.stderr new file mode 100644 index 0000000000000..11550bf801ab0 --- /dev/null +++ b/src/test/ui/consts/control-flow/assert.panic.stderr @@ -0,0 +1,21 @@ +error[E0658]: `if` is not allowed in a `const` + --> $DIR/assert.rs:8:15 + | +LL | const _: () = assert!(true); + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/assert.rs:12:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs new file mode 100644 index 0000000000000..2da42d5084bc1 --- /dev/null +++ b/src/test/ui/consts/control-flow/assert.rs @@ -0,0 +1,17 @@ +// Test that `assert` works only when both `const_if_match` and `const_panic` are enabled. + +// revisions: stock if_match panic both + +#![cfg_attr(any(both, if_match), feature(const_if_match))] +#![cfg_attr(any(both, panic), feature(const_panic))] + +const _: () = assert!(true); +//[stock,panic]~^ ERROR `if` is not allowed in a `const` +//[if_match]~^^ ERROR panicking in constants is unstable + +const _: () = assert!(false); +//[stock,panic]~^ ERROR `if` is not allowed in a `const` +//[if_match]~^^ ERROR panicking in constants is unstable +//[both]~^^^ ERROR any use of this value will cause an error + +fn main() {} diff --git a/src/test/ui/consts/control-flow/assert.stock.stderr b/src/test/ui/consts/control-flow/assert.stock.stderr new file mode 100644 index 0000000000000..11550bf801ab0 --- /dev/null +++ b/src/test/ui/consts/control-flow/assert.stock.stderr @@ -0,0 +1,21 @@ +error[E0658]: `if` is not allowed in a `const` + --> $DIR/assert.rs:8:15 + | +LL | const _: () = assert!(true); + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/assert.rs:12:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs new file mode 100644 index 0000000000000..8bd1929956fd3 --- /dev/null +++ b/src/test/ui/consts/control-flow/basics.rs @@ -0,0 +1,43 @@ +// Test basic functionality of `if` and `match` in a const context. + +// run-pass + +#![feature(const_panic)] +#![feature(const_if_match)] + +const X: u32 = 4; +const Y: u32 = 5; + +const ABS_DIFF: u32 = if X < Y { + Y - X +} else { + X - Y +}; + +const fn abs_diff(a: u32, b: u32) -> u32 { + match (a, b) { + (big, little) if big > little => big - little, + (little, big) => big - little, + } +} + +const fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + return a; + } + + gcd(b, a % b) +} + +fn main() { + const _: () = assert!(abs_diff(4, 5) == abs_diff(5, 4)); + assert_eq!(abs_diff(4, 5), abs_diff(5, 4)); + + const _: () = assert!(ABS_DIFF == abs_diff(5, 4)); + assert_eq!(ABS_DIFF, abs_diff(5, 4)); + + const _: () = assert!(gcd(48, 18) == 6); + const _: () = assert!(gcd(18, 48) == 6); + assert_eq!(gcd(48, 18), 6); + assert_eq!(gcd(18, 48), 6); +} diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-failure.rs new file mode 100644 index 0000000000000..c6bea89e6e6f7 --- /dev/null +++ b/src/test/ui/consts/control-flow/drop-failure.rs @@ -0,0 +1,35 @@ +#![feature(const_if_match)] + +// `x` is *not* always moved into the final value may be dropped inside the initializer. +const _: Option> = { + let y: Option> = None; + let x = Some(Vec::new()); + //~^ ERROR destructors cannot be evaluated at compile-time + + if true { + x + } else { + y + } +}; + +// We only clear `NeedsDrop` if a local is moved from in entirely. This is a shortcoming of the +// existing analysis. +const _: Vec = { + let vec_tuple = (Vec::new(),); + //~^ ERROR destructors cannot be evaluated at compile-time + + vec_tuple.0 +}; + +// This applies to single-field enum variants as well. +const _: Vec = { + let x: Result<_, Vec> = Ok(Vec::new()); + //~^ ERROR destructors cannot be evaluated at compile-time + + match x { + Ok(x) | Err(x) => x, + } +}; + +fn main() {} diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-failure.stderr new file mode 100644 index 0000000000000..35ceb3b277084 --- /dev/null +++ b/src/test/ui/consts/control-flow/drop-failure.stderr @@ -0,0 +1,21 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/drop-failure.rs:6:9 + | +LL | let x = Some(Vec::new()); + | ^ constants cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/drop-failure.rs:19:9 + | +LL | let vec_tuple = (Vec::new(),); + | ^^^^^^^^^ constants cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/drop-failure.rs:27:9 + | +LL | let x: Result<_, Vec> = Ok(Vec::new()); + | ^ constants cannot evaluate destructors + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/control-flow/drop-success.rs b/src/test/ui/consts/control-flow/drop-success.rs new file mode 100644 index 0000000000000..92b3f6ec92eb5 --- /dev/null +++ b/src/test/ui/consts/control-flow/drop-success.rs @@ -0,0 +1,24 @@ +// run-pass + +#![feature(const_if_match)] + +// `x` is always moved into the final value and is not dropped inside the initializer. +const _: Option> = { + let y: Option> = None; + let x = Some(Vec::new()); + + if true { + x + } else { + x + } +}; + +const _: Option> = { + let x = Some(Vec::new()); + match () { + () => x, + } +}; + +fn main() {} diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr new file mode 100644 index 0000000000000..21e3f2af15ad6 --- /dev/null +++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr @@ -0,0 +1,14 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate-const-if-match.rs:108:1 + | +LL | / fn main() { +LL | | let _ = [0; { +LL | | let x = if false { 0 } else { 1 }; +LL | | +... | +LL | | }]; +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs new file mode 100644 index 0000000000000..00576d50ac66b --- /dev/null +++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs @@ -0,0 +1,118 @@ +// Ensure that `if`, `if let` and `match` are only allowed in the various const contexts when +// `#![feature(const_if_match)]` is enabled. When the feature gate is removed, the `#[rustc_error]` +// on `main` should be removed and this test converted to `check-pass`. + +// revisions: stock if_match + +#![feature(rustc_attrs)] +#![cfg_attr(if_match, feature(const_if_match))] + +const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const` + 5 +} else { + 6 +}; + +const _: i32 = if let Some(true) = Some(false) { //[stock]~ ERROR `if` is not allowed in a `const` + 0 +} else { + 1 +}; + +const _: i32 = match 1 { //[stock]~ ERROR `match` is not allowed in a `const` + 2 => 3, + 4 => 5, + _ => 0, +}; + +static FOO: i32 = { + let x = if true { 0 } else { 1 }; + //[stock]~^ ERROR `if` is not allowed in a `static` + let x = match x { 0 => 1, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `static` + if let Some(x) = Some(x) { x } else { 1 } + //[stock]~^ ERROR `if` is not allowed in a `static` +}; + +static mut BAR: i32 = { + let x = if true { 0 } else { 1 }; + //[stock]~^ ERROR `if` is not allowed in a `static mut` + let x = match x { 0 => 1, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `static mut` + if let Some(x) = Some(x) { x } else { 1 } + //[stock]~^ ERROR `if` is not allowed in a `static mut` +}; + +const fn if_() -> i32 { + if true { 5 } else { 6 } //[stock]~ ERROR `if` is not allowed in a `const fn` +} + +const fn if_let(a: Option) -> i32 { + if let Some(true) = a { //[stock]~ ERROR `if` is not allowed in a `const fn` + 0 + } else { + 1 + } +} + +const fn match_(i: i32) -> i32 { + match i { //[stock]~ ERROR `match` is not allowed in a `const fn` + i if i > 10 => i, + 1 => 2, + _ => 0 + } +} + +pub trait Foo { + const IF: i32 = if true { 5 } else { 6 }; + //[stock]~^ ERROR `if` is not allowed in a `const` + + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + //[stock]~^ ERROR `if` is not allowed in a `const` + + const MATCH: i32 = match 0 { 1 => 2, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `const` +} + +impl Foo for () { + const IF: i32 = if true { 5 } else { 6 }; + //[stock]~^ ERROR `if` is not allowed in a `const` + + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + //[stock]~^ ERROR `if` is not allowed in a `const` + + const MATCH: i32 = match 0 { 1 => 2, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `const` +} + +fn non_const_outside() { + const fn const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + //[stock]~^ ERROR `if` is not allowed in a `const fn` + let x = match x { 0 => 1, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `const fn` + if let Some(x) = Some(x) { x } else { 1 } + //[stock]~^ ERROR `if` is not allowed in a `const fn` + } +} + +const fn const_outside() { + fn non_const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + let x = match x { 0 => 1, _ => 0 }; + if let Some(x) = Some(x) { x } else { 1 } + } +} + +#[rustc_error] +fn main() { //[if_match]~ ERROR fatal error triggered by #[rustc_error] + let _ = [0; { + let x = if false { 0 } else { 1 }; + //[stock]~^ ERROR `if` is not allowed in a `const` + let x = match x { 0 => 1, _ => 0 }; + //[stock]~^ ERROR `match` is not allowed in a `const` + if let Some(x) = Some(x) { x } else { 1 } + //[stock]~^ ERROR `if` is not allowed in a `const` + //[stock]~| ERROR constant contains unimplemented expression type + }]; +} diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr new file mode 100644 index 0000000000000..d3c6a51923ffb --- /dev/null +++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr @@ -0,0 +1,249 @@ +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:10:16 + | +LL | const _: i32 = if true { + | ________________^ +LL | | 5 +LL | | } else { +LL | | 6 +LL | | }; + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:16:16 + | +LL | const _: i32 = if let Some(true) = Some(false) { + | ________________^ +LL | | 0 +LL | | } else { +LL | | 1 +LL | | }; + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:22:16 + | +LL | const _: i32 = match 1 { + | ________________^ +LL | | 2 => 3, +LL | | 4 => 5, +LL | | _ => 0, +LL | | }; + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `static` + --> $DIR/feature-gate-const-if-match.rs:29:13 + | +LL | let x = if true { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `static` + --> $DIR/feature-gate-const-if-match.rs:31:13 + | +LL | let x = match x { 0 => 1, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `static` + --> $DIR/feature-gate-const-if-match.rs:33:5 + | +LL | if let Some(x) = Some(x) { x } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `static mut` + --> $DIR/feature-gate-const-if-match.rs:38:13 + | +LL | let x = if true { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `static mut` + --> $DIR/feature-gate-const-if-match.rs:40:13 + | +LL | let x = match x { 0 => 1, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `static mut` + --> $DIR/feature-gate-const-if-match.rs:42:5 + | +LL | if let Some(x) = Some(x) { x } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:47:5 + | +LL | if true { 5 } else { 6 } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:51:5 + | +LL | / if let Some(true) = a { +LL | | 0 +LL | | } else { +LL | | 1 +LL | | } + | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:59:5 + | +LL | / match i { +LL | | i if i > 10 => i, +LL | | 1 => 2, +LL | | _ => 0 +LL | | } + | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:90:17 + | +LL | let x = if y { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:92:17 + | +LL | let x = match x { 0 => 1, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const fn` + --> $DIR/feature-gate-const-if-match.rs:94:9 + | +LL | if let Some(x) = Some(x) { x } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:110:17 + | +LL | let x = if false { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:112:17 + | +LL | let x = match x { 0 => 1, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:114:9 + | +LL | if let Some(x) = Some(x) { x } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:67:21 + | +LL | const IF: i32 = if true { 5 } else { 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:70:25 + | +LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:73:24 + | +LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:78:21 + | +LL | const IF: i32 = if true { 5 } else { 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:81:25 + | +LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `match` is not allowed in a `const` + --> $DIR/feature-gate-const-if-match.rs:84:24 + | +LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0019]: constant contains unimplemented expression type + --> $DIR/feature-gate-const-if-match.rs:114:21 + | +LL | if let Some(x) = Some(x) { x } else { 1 } + | ^ + +error: aborting due to 25 previous errors + +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/control-flow/interior-mutability.rs b/src/test/ui/consts/control-flow/interior-mutability.rs new file mode 100644 index 0000000000000..fcced75fcb047 --- /dev/null +++ b/src/test/ui/consts/control-flow/interior-mutability.rs @@ -0,0 +1,27 @@ +// Ensure that *any* assignment to the return place of a value with interior mutability +// disqualifies it from promotion. + +#![feature(const_if_match)] + +use std::cell::Cell; + +const X: Option> = { + let mut x = None; + if false { + x = Some(Cell::new(4)); + } + x +}; + +const Y: Option> = { + let mut y = Some(Cell::new(4)); + if true { + y = None; + } + y +}; + +fn main() { + let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed + let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/control-flow/interior-mutability.stderr b/src/test/ui/consts/control-flow/interior-mutability.stderr new file mode 100644 index 0000000000000..49e8ea3ade7ba --- /dev/null +++ b/src/test/ui/consts/control-flow/interior-mutability.stderr @@ -0,0 +1,24 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:25:26 + | +LL | let x: &'static _ = &X; + | ---------- ^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let y: &'static _ = &Y; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:26:26 + | +LL | let y: &'static _ = &Y; + | ---------- ^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/control-flow/issue-46843.if_match.stderr b/src/test/ui/consts/control-flow/issue-46843.if_match.stderr new file mode 100644 index 0000000000000..4c64d7dee8c01 --- /dev/null +++ b/src/test/ui/consts/control-flow/issue-46843.if_match.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-46843.rs:11:26 + | +LL | pub const Q: i32 = match non_const() { + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/control-flow/issue-46843.rs b/src/test/ui/consts/control-flow/issue-46843.rs new file mode 100644 index 0000000000000..1fc91015ffa70 --- /dev/null +++ b/src/test/ui/consts/control-flow/issue-46843.rs @@ -0,0 +1,18 @@ +// revisions: stock if_match + +#![cfg_attr(if_match, feature(const_if_match))] + +enum Thing { This, That } + +fn non_const() -> Thing { + Thing::This +} + +pub const Q: i32 = match non_const() { + //[stock]~^ ERROR `match` is not allowed in a `const` + //[if_match]~^^ ERROR calls in constants are limited to constant functions + Thing::This => 1, + Thing::That => 0 +}; + +fn main() {} diff --git a/src/test/ui/consts/control-flow/issue-46843.stock.stderr b/src/test/ui/consts/control-flow/issue-46843.stock.stderr new file mode 100644 index 0000000000000..b6f38f8ed95e1 --- /dev/null +++ b/src/test/ui/consts/control-flow/issue-46843.stock.stderr @@ -0,0 +1,18 @@ +error[E0658]: `match` is not allowed in a `const` + --> $DIR/issue-46843.rs:11:20 + | +LL | pub const Q: i32 = match non_const() { + | ____________________^ +LL | | +LL | | +LL | | Thing::This => 1, +LL | | Thing::That => 0 +LL | | }; + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/issue-50577.if_match.stderr b/src/test/ui/consts/control-flow/issue-50577.if_match.stderr new file mode 100644 index 0000000000000..79572c417024f --- /dev/null +++ b/src/test/ui/consts/control-flow/issue-50577.if_match.stderr @@ -0,0 +1,16 @@ +error[E0317]: if may be missing an else clause + --> $DIR/issue-50577.rs:7:16 + | +LL | Drop = assert_eq!(1, 1) + | ^^^^^^^^^^^^^^^^ + | | + | expected `()`, found `isize` + | found here + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/consts/control-flow/issue-50577.rs b/src/test/ui/consts/control-flow/issue-50577.rs new file mode 100644 index 0000000000000..7906ec4dc68c7 --- /dev/null +++ b/src/test/ui/consts/control-flow/issue-50577.rs @@ -0,0 +1,13 @@ +// revisions: stock if_match + +#![cfg_attr(if_match, feature(const_if_match))] + +fn main() { + enum Foo { + Drop = assert_eq!(1, 1) + //[stock,if_match]~^ ERROR if may be missing an else clause + //[stock]~^^ ERROR `match` is not allowed in a `const` + //[stock]~| ERROR `match` is not allowed in a `const` + //[stock]~| ERROR `if` is not allowed in a `const` + } +} diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/consts/control-flow/issue-50577.stock.stderr similarity index 61% rename from src/test/ui/issues/issue-50577.stderr rename to src/test/ui/consts/control-flow/issue-50577.stock.stderr index 0a150fbf53a0c..13b50954292ea 100644 --- a/src/test/ui/issues/issue-50577.stderr +++ b/src/test/ui/consts/control-flow/issue-50577.stock.stderr @@ -1,29 +1,35 @@ -error[E0744]: `match` is not allowed in a `const` - --> $DIR/issue-50577.rs:3:16 +error[E0658]: `match` is not allowed in a `const` + --> $DIR/issue-50577.rs:7:16 | LL | Drop = assert_eq!(1, 1) | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0744]: `if` is not allowed in a `const` - --> $DIR/issue-50577.rs:3:16 +error[E0658]: `if` is not allowed in a `const` + --> $DIR/issue-50577.rs:7:16 | LL | Drop = assert_eq!(1, 1) | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0744]: `match` is not allowed in a `const` - --> $DIR/issue-50577.rs:3:16 +error[E0658]: `match` is not allowed in a `const` + --> $DIR/issue-50577.rs:7:16 | LL | Drop = assert_eq!(1, 1) | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error[E0317]: if may be missing an else clause - --> $DIR/issue-50577.rs:3:16 + --> $DIR/issue-50577.rs:7:16 | LL | Drop = assert_eq!(1, 1) | ^^^^^^^^^^^^^^^^ @@ -37,5 +43,5 @@ LL | Drop = assert_eq!(1, 1) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0317, E0744. +Some errors have detailed explanations: E0317, E0658. For more information about an error, try `rustc --explain E0317`. diff --git a/src/test/ui/consts/const-loop.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr similarity index 67% rename from src/test/ui/consts/const-loop.stderr rename to src/test/ui/consts/control-flow/loop.if_match.stderr index 2c96d18175983..15b9eb028611e 100644 --- a/src/test/ui/consts/const-loop.stderr +++ b/src/test/ui/consts/control-flow/loop.if_match.stderr @@ -1,35 +1,35 @@ error[E0744]: `loop` is not allowed in a `const` - --> $DIR/const-loop.rs:1:15 + --> $DIR/loop.rs:8:15 | LL | const _: () = loop {}; | ^^^^^^^ error[E0744]: `loop` is not allowed in a `static` - --> $DIR/const-loop.rs:3:19 + --> $DIR/loop.rs:10:19 | LL | static FOO: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/const-loop.rs:6:5 + --> $DIR/loop.rs:13:5 | LL | loop {} | ^^^^^^^ error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/const-loop.rs:19:9 + --> $DIR/loop.rs:26:9 | LL | loop {} | ^^^^^^^ error[E0744]: `while` is not allowed in a `const` - --> $DIR/const-loop.rs:31:9 + --> $DIR/loop.rs:38:9 | LL | while false {} | ^^^^^^^^^^^^^^ error[E0744]: `while` is not allowed in a `const` - --> $DIR/const-loop.rs:40:5 + --> $DIR/loop.rs:47:5 | LL | / while x < 4 { LL | | x += 1; @@ -37,7 +37,7 @@ LL | | } | |_____^ error[E0744]: `while` is not allowed in a `const` - --> $DIR/const-loop.rs:44:5 + --> $DIR/loop.rs:51:5 | LL | / while x < 8 { LL | | x += 1; @@ -45,7 +45,7 @@ LL | | } | |_____^ error[E0744]: `for` is not allowed in a `const` - --> $DIR/const-loop.rs:54:5 + --> $DIR/loop.rs:61:5 | LL | / for i in 0..4 { LL | | x += i; @@ -53,7 +53,7 @@ LL | | } | |_____^ error[E0744]: `for` is not allowed in a `const` - --> $DIR/const-loop.rs:58:5 + --> $DIR/loop.rs:65:5 | LL | / for i in 0..4 { LL | | x += i; @@ -61,7 +61,7 @@ LL | | } | |_____^ error[E0744]: `loop` is not allowed in a `const` - --> $DIR/const-loop.rs:68:5 + --> $DIR/loop.rs:75:5 | LL | / loop { LL | | x += 1; @@ -71,16 +71,8 @@ LL | | } LL | | } | |_____^ -error[E0744]: `if` is not allowed in a `const` - --> $DIR/const-loop.rs:70:9 - | -LL | / if x == 4 { -LL | | break; -LL | | } - | |_________^ - error[E0744]: `loop` is not allowed in a `const` - --> $DIR/const-loop.rs:75:5 + --> $DIR/loop.rs:82:5 | LL | / loop { LL | | x += 1; @@ -90,38 +82,30 @@ LL | | } LL | | } | |_____^ -error[E0744]: `if` is not allowed in a `const` - --> $DIR/const-loop.rs:77:9 - | -LL | / if x == 8 { -LL | | break; -LL | | } - | |_________^ - -error[E0744]: `while let` is not allowed in a `const` - --> $DIR/const-loop.rs:87:5 +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:94:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0744]: `while let` is not allowed in a `const` - --> $DIR/const-loop.rs:88:5 +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:95:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0744]: `loop` is not allowed in a `const` - --> $DIR/const-loop.rs:10:22 + --> $DIR/loop.rs:17:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ error[E0744]: `loop` is not allowed in a `const` - --> $DIR/const-loop.rs:14:22 + --> $DIR/loop.rs:21:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/consts/control-flow/loop.rs b/src/test/ui/consts/control-flow/loop.rs new file mode 100644 index 0000000000000..4be341f2d3846 --- /dev/null +++ b/src/test/ui/consts/control-flow/loop.rs @@ -0,0 +1,97 @@ +// Ensure that all loops are forbidden in a const context, even if `#![feature(const_if_match)]` is +// enabled. + +// revisions: stock if_match + +#![cfg_attr(if_match, feature(const_if_match))] + +const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const` + +static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static` + +const fn foo() { + loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn` +} + +pub trait Foo { + const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const` +} + +impl Foo for () { + const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const` +} + +fn non_const_outside() { + const fn const_inside() { + loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn` + } +} + +const fn const_outside() { + fn non_const_inside() { + loop {} + } +} + +fn main() { + let x = [0; { + while false {} + //[stock,if_match]~^ ERROR `while` is not allowed in a `const` + 4 + }]; +} + +const _: i32 = { + let mut x = 0; + + while x < 4 { //[stock,if_match]~ ERROR `while` is not allowed in a `const` + x += 1; + } + + while x < 8 { //[stock,if_match]~ ERROR `while` is not allowed in a `const` + x += 1; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const` + x += i; + } + + for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const` + x += i; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const` + x += 1; + if x == 4 { //[stock]~ ERROR `if` is not allowed in a `const` + break; + } + } + + loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const` + x += 1; + if x == 8 { //[stock]~ ERROR `if` is not allowed in a `const` + break; + } + } + + x +}; + +const _: i32 = { + let mut x = 0; + while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const` + while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const` + x +}; diff --git a/src/test/ui/consts/control-flow/loop.stock.stderr b/src/test/ui/consts/control-flow/loop.stock.stderr new file mode 100644 index 0000000000000..bb651d23179f7 --- /dev/null +++ b/src/test/ui/consts/control-flow/loop.stock.stderr @@ -0,0 +1,134 @@ +error[E0744]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:8:15 + | +LL | const _: () = loop {}; + | ^^^^^^^ + +error[E0744]: `loop` is not allowed in a `static` + --> $DIR/loop.rs:10:19 + | +LL | static FOO: i32 = loop { break 4; }; + | ^^^^^^^^^^^^^^^^^ + +error[E0744]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:13:5 + | +LL | loop {} + | ^^^^^^^ + +error[E0744]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:26:9 + | +LL | loop {} + | ^^^^^^^ + +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:38:9 + | +LL | while false {} + | ^^^^^^^^^^^^^^ + +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:47:5 + | +LL | / while x < 4 { +LL | | x += 1; +LL | | } + | |_____^ + +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:51:5 + | +LL | / while x < 8 { +LL | | x += 1; +LL | | } + | |_____^ + +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:61:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:65:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error[E0744]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:75:5 + | +LL | / loop { +LL | | x += 1; +LL | | if x == 4 { +LL | | break; +LL | | } +LL | | } + | |_____^ + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/loop.rs:77:9 + | +LL | / if x == 4 { +LL | | break; +LL | | } + | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0744]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:82:5 + | +LL | / loop { +LL | | x += 1; +LL | | if x == 8 { +LL | | break; +LL | | } +LL | | } + | |_____^ + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/loop.rs:84:9 + | +LL | / if x == 8 { +LL | | break; +LL | | } + | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:94:5 + | +LL | while let None = Some(x) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0744]: `while` is not allowed in a `const` + --> $DIR/loop.rs:95:5 + | +LL | while let None = Some(x) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0744]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:17:22 + | +LL | const BAR: i32 = loop { break 4; }; + | ^^^^^^^^^^^^^^^^^ + +error[E0744]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:21:22 + | +LL | const BAR: i32 = loop { break 4; }; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0658, E0744. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs new file mode 100644 index 0000000000000..8cee2a54f56d3 --- /dev/null +++ b/src/test/ui/consts/control-flow/short-circuit-let.rs @@ -0,0 +1,39 @@ +// `&&` and `||` were previously forbidden in constants alongside let bindings. + +// run-pass + +#![feature(const_if_match)] +#![feature(const_panic)] + +const X: i32 = { + let mut x = 0; + let _ = true && { x = 1; false }; + x +}; + +const Y: bool = { + let x = true && false || true; + x +}; + +const fn truthy() -> bool { + let x = true || return false; + x +} + +const fn falsy() -> bool { + let x = true && return false; + x +} + +fn main() { + const _: () = assert!(Y); + assert!(Y); + + const _: () = assert!(X == 1); + assert_eq!(X, 1); + + const _: () = assert!(truthy()); + const _: () = assert!(!falsy()); + assert!(truthy() && !falsy()); +} diff --git a/src/test/ui/consts/control-flow/short-circuit.if_match.stderr b/src/test/ui/consts/control-flow/short-circuit.if_match.stderr new file mode 100644 index 0000000000000..f6ba28e7b7246 --- /dev/null +++ b/src/test/ui/consts/control-flow/short-circuit.if_match.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/short-circuit.rs:14:1 + | +LL | fn main() {} + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/control-flow/short-circuit.rs b/src/test/ui/consts/control-flow/short-circuit.rs new file mode 100644 index 0000000000000..f5e54a69d4a6f --- /dev/null +++ b/src/test/ui/consts/control-flow/short-circuit.rs @@ -0,0 +1,14 @@ +// Test that both `&&` and `||` actually short-circuit when the `const_if_match` feature flag is +// enabled. Without the feature flag, both sides are evaluated unconditionally. + +// revisions: stock if_match + +#![feature(rustc_attrs)] +#![feature(const_panic)] +#![cfg_attr(if_match, feature(const_if_match))] + +const _: bool = true || panic!(); //[stock]~ ERROR any use of this value will cause an error +const _: bool = false && panic!(); //[stock]~ ERROR any use of this value will cause an error + +#[rustc_error] +fn main() {} //[if_match]~ ERROR fatal error triggered by #[rustc_error] diff --git a/src/test/ui/consts/control-flow/short-circuit.stock.stderr b/src/test/ui/consts/control-flow/short-circuit.stock.stderr new file mode 100644 index 0000000000000..cf0de929593db --- /dev/null +++ b/src/test/ui/consts/control-flow/short-circuit.stock.stderr @@ -0,0 +1,23 @@ +error: any use of this value will cause an error + --> $DIR/short-circuit.rs:10:25 + | +LL | const _: bool = true || panic!(); + | ------------------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:10:25 + | + = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: any use of this value will cause an error + --> $DIR/short-circuit.rs:11:26 + | +LL | const _: bool = false && panic!(); + | -------------------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:11:26 + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs new file mode 100644 index 0000000000000..823605ff034f1 --- /dev/null +++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs @@ -0,0 +1,27 @@ +// check-pass + +#![feature(const_if_match)] + +enum Foo { + Prob, +} + +const FOO: u32 = match Foo::Prob { + Foo::Prob => 42, +}; + +const BAR: u32 = match Foo::Prob { + x => 42, +}; + +impl Foo { + pub const fn as_val(&self) -> u8 { + use self::Foo::*; + + match *self { + Prob => 0x1, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/control-flow/try.rs b/src/test/ui/consts/control-flow/try.rs new file mode 100644 index 0000000000000..31fe09d4f6962 --- /dev/null +++ b/src/test/ui/consts/control-flow/try.rs @@ -0,0 +1,12 @@ +// The `?` operator is still not const-evaluatable because it calls `From::from` on the error +// variant. + +#![feature(const_if_match)] + +const fn opt() -> Option { + let x = Some(2); + x?; //~ ERROR `?` is not allowed in a `const fn` + None +} + +fn main() {} diff --git a/src/test/ui/consts/control-flow/try.stderr b/src/test/ui/consts/control-flow/try.stderr new file mode 100644 index 0000000000000..60a386ef6c870 --- /dev/null +++ b/src/test/ui/consts/control-flow/try.stderr @@ -0,0 +1,9 @@ +error[E0744]: `?` is not allowed in a `const fn` + --> $DIR/try.rs:8:5 + | +LL | x?; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs deleted file mode 100644 index 80a92c4c96558..0000000000000 --- a/src/test/ui/consts/single_variant_match_ice.rs +++ /dev/null @@ -1,23 +0,0 @@ -enum Foo { - Prob, -} - -const FOO: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const` - Foo::Prob => 42, -}; - -const BAR: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const` - x => 42, -}; - -impl Foo { - pub const fn as_val(&self) -> u8 { - use self::Foo::*; - - match *self { //~ ERROR `match` is not allowed in a `const fn` - Prob => 0x1, - } - } -} - -fn main() {} diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr deleted file mode 100644 index 780dd0dcddf49..0000000000000 --- a/src/test/ui/consts/single_variant_match_ice.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0744]: `match` is not allowed in a `const` - --> $DIR/single_variant_match_ice.rs:5:18 - | -LL | const FOO: u32 = match Foo::Prob { - | __________________^ -LL | | Foo::Prob => 42, -LL | | }; - | |_^ - -error[E0744]: `match` is not allowed in a `const` - --> $DIR/single_variant_match_ice.rs:9:18 - | -LL | const BAR: u32 = match Foo::Prob { - | __________________^ -LL | | x => 42, -LL | | }; - | |_^ - -error[E0744]: `match` is not allowed in a `const fn` - --> $DIR/single_variant_match_ice.rs:17:9 - | -LL | / match *self { -LL | | Prob => 0x1, -LL | | } - | |_________^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs b/src/test/ui/enum-discriminant/niche.rs similarity index 96% rename from src/test/ui/consts/miri_unleashed/enum_discriminants.rs rename to src/test/ui/enum-discriminant/niche.rs index 76d62f069f378..8d2cdf34f373e 100644 --- a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs +++ b/src/test/ui/enum-discriminant/niche.rs @@ -1,8 +1,7 @@ -// compile-flags: -Zunleash-the-miri-inside-of-you -Awarnings // run-pass -// miri unleashed warnings are not useful and change frequently, so they are silenced above. #![feature(const_panic)] +#![feature(const_if_match)] //! Make sure that we read and write enum discriminants correctly for corner cases caused //! by layout optimizations. diff --git a/src/test/ui/issues/issue-46843.rs b/src/test/ui/issues/issue-46843.rs deleted file mode 100644 index e5b271367393d..0000000000000 --- a/src/test/ui/issues/issue-46843.rs +++ /dev/null @@ -1,13 +0,0 @@ -enum Thing { This, That } - -fn non_const() -> Thing { - Thing::This -} - -pub const Q: i32 = match non_const() { - //~^ ERROR `match` is not allowed in a `const` - Thing::This => 1, - Thing::That => 0 -}; - -fn main() {} diff --git a/src/test/ui/issues/issue-46843.stderr b/src/test/ui/issues/issue-46843.stderr deleted file mode 100644 index 9d5332978644e..0000000000000 --- a/src/test/ui/issues/issue-46843.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0744]: `match` is not allowed in a `const` - --> $DIR/issue-46843.rs:7:20 - | -LL | pub const Q: i32 = match non_const() { - | ____________________^ -LL | | -LL | | Thing::This => 1, -LL | | Thing::That => 0 -LL | | }; - | |_^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs deleted file mode 100644 index f3f680e7b8ecd..0000000000000 --- a/src/test/ui/issues/issue-50577.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - enum Foo { - Drop = assert_eq!(1, 1) - //~^ ERROR if may be missing an else clause - //~| ERROR `match` is not allowed in a `const` - //~| ERROR `match` is not allowed in a `const` - //~| ERROR `if` is not allowed in a `const` - } -} diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs index e0fd7ff896cd3..782037a1fe5d4 100644 --- a/src/test/ui/issues/issue-51714.rs +++ b/src/test/ui/issues/issue-51714.rs @@ -10,5 +10,5 @@ fn main() { [(); return while let Some(n) = Some(0) {}]; //~^ ERROR return statement outside of function body - //~| ERROR `while let` is not allowed in a `const` + //~| ERROR `while` is not allowed in a `const` } diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr index a3b20cf97f87d..001928c3b2f31 100644 --- a/src/test/ui/issues/issue-51714.stderr +++ b/src/test/ui/issues/issue-51714.stderr @@ -1,4 +1,4 @@ -error[E0744]: `while let` is not allowed in a `const` +error[E0744]: `while` is not allowed in a `const` --> $DIR/issue-51714.rs:11:17 | LL | [(); return while let Some(n) = Some(0) {}]; diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 8d88aefdb5185..c4fb68c02784e 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -33,19 +33,19 @@ fn main() { } while let Some(_) = Some(()) { - if break () { //~ ERROR `break` with value from a `while let` loop + if break () { //~ ERROR `break` with value from a `while` loop } } while let Some(_) = Some(()) { break None; - //~^ ERROR `break` with value from a `while let` loop + //~^ ERROR `break` with value from a `while` loop } 'while_let_loop: while let Some(_) = Some(()) { loop { break 'while_let_loop "nope"; - //~^ ERROR `break` with value from a `while let` loop + //~^ ERROR `break` with value from a `while` loop break 33; }; } diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index 1707a179ad0c0..1f2d81ff03f0a 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -28,35 +28,35 @@ help: instead, use `break` on its own without a value inside this `while` loop LL | break; | ^^^^^ -error[E0571]: `break` with value from a `while let` loop +error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:36:12 | LL | if break () { | ^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: instead, use `break` on its own without a value inside this `while let` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | if break { | ^^^^^ -error[E0571]: `break` with value from a `while let` loop +error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:41:9 | LL | break None; | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: instead, use `break` on its own without a value inside this `while let` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | break; | ^^^^^ -error[E0571]: `break` with value from a `while let` loop +error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:47:13 | LL | break 'while_let_loop "nope"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: instead, use `break` on its own without a value inside this `while let` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | break; | ^^^^^ diff --git a/src/test/ui/return/return-match-array-const.stderr b/src/test/ui/return/return-match-array-const.stderr index 496e9208b6106..8b8e961b726d7 100644 --- a/src/test/ui/return/return-match-array-const.stderr +++ b/src/test/ui/return/return-match-array-const.stderr @@ -1,20 +1,29 @@ -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/return-match-array-const.rs:2:17 | LL | [(); return match 0 { n => n }]; | ^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/return-match-array-const.rs:6:17 | LL | [(); return match 0 { 0 => 0 }]; | ^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/return-match-array-const.rs:10:17 | LL | [(); return match () { 'a' => 0, _ => 0 }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0572]: return statement outside of function body --> $DIR/return-match-array-const.rs:2:10 @@ -36,5 +45,5 @@ LL | [(); return match () { 'a' => 0, _ => 0 }]; error: aborting due to 6 previous errors -Some errors have detailed explanations: E0572, E0744. +Some errors have detailed explanations: E0572, E0658. For more information about an error, try `rustc --explain E0572`. diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 05e30a8010aa1..f24ea0505e785 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -513,23 +513,32 @@ warning: the feature `let_chains` is incomplete and may cause the compiler to cr LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. | ^^^^^^^^^^ -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/disallowed-positions.rs:218:17 | LL | true && let 1 = 1 | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/disallowed-positions.rs:223:17 | LL | true && let 1 = 1 | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `match` is not allowed in a `const` +error[E0658]: `match` is not allowed in a `const` --> $DIR/disallowed-positions.rs:228:17 | LL | true && let 1 = 1 | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:32:8 @@ -952,5 +961,5 @@ LL | let 0 = 0?; error: aborting due to 106 previous errors -Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0744. +Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0658. For more information about an error, try `rustc --explain E0277`. From 25122d09ebd27b39830e662a9e7ef3ccfd68dd95 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 18 Nov 2019 15:31:04 -0800 Subject: [PATCH 09/10] Const-check the discriminant of a `SwitchInt` --- src/librustc_mir/transform/qualify_min_const_fn.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index cb6f94adbf08c..c5fa9df528cc6 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -333,9 +333,11 @@ fn check_terminator( span, "loops and conditional expressions are not stable in const fn".into(), )), - | TerminatorKind::FalseEdges { .. } - | TerminatorKind::SwitchInt { .. } - => Ok(()), + + TerminatorKind::FalseEdges { .. } => Ok(()), + TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => { + check_operand(tcx, discr, span, def_id, body) + } | TerminatorKind::Abort | TerminatorKind::Unreachable => { Err((span, "const fn with unreachable code is not stable".into())) From b09bb1569b23eaadcf22d7420f1ba9872c1088f7 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 19 Nov 2019 12:22:39 -0800 Subject: [PATCH 10/10] Allow `Downcast` projections in `qualify_min_const_fn` --- src/librustc_mir/transform/qualify_min_const_fn.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c5fa9df528cc6..2bc44d2e5c142 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -266,9 +266,10 @@ fn check_place( while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { - ProjectionElem::Downcast(..) => { - return Err((span, "`match` or `if let` in `const fn` is unstable".into())); - } + ProjectionElem::Downcast(..) if !tcx.features().const_if_match + => return Err((span, "`match` or `if let` in `const fn` is unstable".into())), + ProjectionElem::Downcast(_symbol, _variant_index) => {} + ProjectionElem::Field(..) => { let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty; if let Some(def) = base_ty.ty_adt_def() {