1
Fork 0

Auto merge of #66507 - ecstatic-morse:const-if-match, r=oli-obk

Enable `if` and `match` in constants behind a feature flag

This PR is an initial implementation of #49146. It introduces a `const_if_match` feature flag and does the following if it is enabled:
- Allows `Downcast` projections, `SwitchInt` terminators and `FakeRead`s for matched places through the MIR const-checker.
- Allows `if` and `match` expressions through the HIR const-checker.
- Stops converting `&&` to `&` and `||` to `|` in `const` and `static` items.

As a result, the following operations are now allowed in a const context behind the feature flag:
- `if` and `match`
- short circuiting logic operators (`&&` and `||`)
- the `assert` and `debug_assert` macros (if the `const_panic` feature flag is also enabled)

However, the following operations remain forbidden:
- `while`, `loop` and `for` (see #52000)
- the `?` operator (calls `From::from` on its error variant)
- the `assert_eq` and `assert_ne` macros, along with their `debug` variants (calls `fmt::Debug`)

This PR is possible now that we use dataflow for const qualification (see #64470 and #66385).

r? @oli-obk
cc @rust-lang/wg-const-eval @eddyb
This commit is contained in:
bors 2019-11-23 01:13:41 +00:00
commit 6d523ee501
57 changed files with 1321 additions and 347 deletions

View file

@ -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`.

View file

@ -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",
}
}

View file

@ -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(),

View file

@ -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<bool> {
Some(tcx.features().const_if_match)
}
}
/// A function call where the callee is a pointer.
#[derive(Debug)]
@ -139,6 +143,10 @@ impl NonConstOp for HeapAllocation {
#[derive(Debug)]
pub struct IfOrMatch;
impl NonConstOp for IfOrMatch {
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
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(

View file

@ -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()))
}
@ -267,9 +269,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() {
@ -321,10 +324,19 @@ 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 { .. } => 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()))
}

View file

@ -11,16 +11,46 @@ 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;
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<bool> {
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,
@ -75,31 +105,51 @@ 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<ConstKind>,
}
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");
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.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.
@ -113,7 +163,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 +172,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));
}
@ -132,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) => {
use hir::MatchSource::*;
let op = match source {
Normal => Some("match"),
IfDesugar { .. } | IfLetDesugar { .. } => Some("if"),
TryDesugar => Some("?"),
AwaitDesugar => Some(".await"),
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);
}
}

View file

@ -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
// -------------------------------------------------------------------------

View file

@ -203,6 +203,7 @@ symbols! {
const_fn,
const_fn_union,
const_generics,
const_if_match,
const_indexing,
const_in_array_repeat_expressions,
const_let,

View file

@ -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`.

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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
};

View file

@ -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`.

View file

@ -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

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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);
}

View file

@ -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<Vec<i32>> = {
let y: Option<Vec<i32>> = 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<i32> = {
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<i32> = {
let x: Result<_, Vec<i32>> = Ok(Vec::new());
//~^ ERROR destructors cannot be evaluated at compile-time
match x {
Ok(x) | Err(x) => x,
}
};
fn main() {}

View file

@ -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<i32>> = Ok(Vec::new());
| ^ constants cannot evaluate destructors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0493`.

View file

@ -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<Vec<i32>> = {
let y: Option<Vec<i32>> = None;
let x = Some(Vec::new());
if true {
x
} else {
x
}
};
const _: Option<Vec<i32>> = {
let x = Some(Vec::new());
match () {
() => x,
}
};
fn main() {}

View file

@ -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

View file

@ -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<bool>) -> 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
}];
}

View file

@ -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`.

View file

@ -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<Cell<i32>> = {
let mut x = None;
if false {
x = Some(Cell::new(4));
}
x
};
const Y: Option<Cell<i32>> = {
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
}

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`.

View file

@ -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`
}
}

View file

@ -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`.

View file

@ -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`.

View file

@ -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
};

View file

@ -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`.

View file

@ -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());
}

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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() {}

View file

@ -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<i32> {
let x = Some(2);
x?; //~ ERROR `?` is not allowed in a `const fn`
None
}
fn main() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`
}
}

View file

@ -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`
}

View file

@ -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) {}];

View file

@ -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;
};
}

View file

@ -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;
| ^^^^^

View file

@ -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`.

View file

@ -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`.