Skip to content

Commit

Permalink
Rollup merge of rust-lang#72437 - ecstatic-morse:stabilize-const-if-m…
Browse files Browse the repository at this point in the history
…atch, r=oli-obk

Stabilize `#![feature(const_if_match)]`

Quoting from the [stabilization report](rust-lang#49146 (comment)):

> `if` and `match` expressions as well as the short-circuiting logic operators `&&` and `||` will become legal in all [const contexts](https://doc.rust-lang.org/reference/const_eval.html#const-context). A const context is any of the following:
>
> - The initializer of a `const`, `static`, `static mut` or enum discriminant.
> - The body of a `const fn`.
> - The value of a const generic (nightly only).
> - The length of an array type (`[u8; 3]`) or an array repeat expression (`[0u8; 3]`).
>
> Furthermore, the short-circuiting logic operators will no longer be lowered to their bitwise equivalents (`&` and `|` respectively) in `const` and `static` initializers (see rust-lang#57175). As a result, `let` bindings can be used alongside short-circuiting logic in those initializers.

Resolves rust-lang#49146.

Ideally, we would resolve 🐳 rust-lang#66753 before this lands on stable, so it might be worth pushing this back a release. Also, this means we should get the process started for rust-lang#52000, otherwise people will have no recourse except recursion for iterative `const fn`.

r? @oli-obk
  • Loading branch information
Manishearth authored Jun 27, 2020
2 parents 394e1b4 + 63078c3 commit c091c5d
Show file tree
Hide file tree
Showing 129 changed files with 348 additions and 1,757 deletions.
14 changes: 0 additions & 14 deletions src/doc/unstable-book/src/language-features/const-if-match.md

This file was deleted.

2 changes: 1 addition & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
#![feature(const_generic_impls_guard)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(cow_is_borrowed)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@
#![feature(const_ascii_ctype_on_intrinsics)]
#![feature(const_alloc_layout)]
#![feature(const_discriminant)]
#![feature(const_if_match)]
#![feature(const_loop)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![cfg_attr(bootstrap, feature(const_loop))]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_overflowing_int_methods)]
Expand Down
6 changes: 3 additions & 3 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1578,7 +1578,7 @@ $EndFeature, "
#[stable(feature = "no_panic_abs", since = "1.13.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
#[allow_internal_unstable(const_if_match)]
#[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
#[inline]
pub const fn wrapping_abs(self) -> Self {
if self.is_negative() {
Expand Down Expand Up @@ -1867,7 +1867,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self
#[stable(feature = "wrapping", since = "1.7.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
#[allow_internal_unstable(const_if_match)]
#[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
pub const fn overflowing_neg(self) -> (Self, bool) {
if self == Self::MIN {
(Self::MIN, true)
Expand Down Expand Up @@ -2160,7 +2160,7 @@ $EndFeature, "
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
#[allow(unused_attributes)]
#[allow_internal_unstable(const_if_match)]
#[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn abs(self) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ast/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)] // For the `transmute` in `P::new`
#![feature(const_panic)]
#![feature(const_transmute)]
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_feature/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ declare_features! (
(accepted, transparent_enums, "1.42.0", Some(60405), None),
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254), None),
/// Allows the use of `if` and `match` in constants.
(accepted, const_if_match, "1.45.0", Some(49146), None),
/// Allows the use of `loop` and `while` in constants.
(accepted, const_loop, "1.45.0", Some(52000), None),

// -------------------------------------------------------------------------
// feature-group-end: accepted features
Expand Down
6 changes: 0 additions & 6 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,9 +518,6 @@ declare_features! (
/// Allows using the `#[register_tool]` 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),

/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),

Expand All @@ -530,9 +527,6 @@ declare_features! (
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),

/// Allows the use of `loop` and `while` in constants.
(active, const_loop, "1.41.0", Some(52000), None),

/// Allows bindings in the subpattern of a binding pattern.
/// For example, you can write `x @ Some(y)`.
(active, bindings_after_at, "1.41.0", Some(65490), None),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_hir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html

#![feature(crate_visibility_modifier)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)] // For the unsizing cast on `&[]`
#![feature(const_panic)]
#![feature(in_band_lifetimes)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_index/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(allow_internal_unstable)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_infer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_panic)]
#![feature(extend_one)]
#![feature(never_type)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_if_match)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(const_transmute)]
Expand Down
13 changes: 0 additions & 13 deletions src/librustc_middle/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html

// ignore-tidy-filelength

use crate::mir::interpret::{GlobalAlloc, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
Expand Down Expand Up @@ -148,14 +146,6 @@ pub struct Body<'tcx> {
/// Debug information pertaining to user variables, including captures.
pub var_debug_info: Vec<VarDebugInfo<'tcx>>,

/// Mark this MIR of a const context other than const functions as having converted a `&&` or
/// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
/// this conversion from happening and use short circuiting, we will cause the following code
/// to change the value of `x`: `let mut x = 42; false && { x = 55; true };`
///
/// List of places where control flow was destroyed. Used for error reporting.
pub control_flow_destroyed: Vec<(Span, String)>,

/// A span representing this MIR, for error reporting.
pub span: Span,

Expand Down Expand Up @@ -185,7 +175,6 @@ impl<'tcx> Body<'tcx> {
arg_count: usize,
var_debug_info: Vec<VarDebugInfo<'tcx>>,
span: Span,
control_flow_destroyed: Vec<(Span, String)>,
generator_kind: Option<GeneratorKind>,
) -> Self {
// We need `arg_count` locals, and one for the return place.
Expand All @@ -212,7 +201,6 @@ impl<'tcx> Body<'tcx> {
span,
required_consts: Vec::new(),
ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
predecessor_cache: PredecessorCache::new(),
}
}
Expand All @@ -236,7 +224,6 @@ impl<'tcx> Body<'tcx> {
spread_arg: None,
span: DUMMY_SP,
required_consts: Vec::new(),
control_flow_destroyed: Vec::new(),
generator_kind: None,
var_debug_info: Vec::new(),
ignore_interior_mut_in_const_validation: false,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Rust MIR: a lowered representation of Rust.
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_if_match)]
#![feature(const_loop)]
#![cfg_attr(bootstrap, feature(const_if_match))]
#![cfg_attr(bootstrap, feature(const_loop))]
#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ fn new_body<'tcx>(
arg_count,
vec![],
span,
vec![],
None,
)
}
Expand Down
26 changes: 0 additions & 26 deletions src/librustc_mir/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,6 @@ impl NonConstOp for HeapAllocation {
}
}

#[derive(Debug)]
pub struct IfOrMatch;
impl NonConstOp for IfOrMatch {
fn feature_gate() -> Option<Symbol> {
Some(sym::const_if_match)
}

fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
// This should be caught by the HIR const-checker.
ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
}
}

#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {}
Expand All @@ -177,19 +164,6 @@ impl NonConstOp for LiveDrop {
}
}

#[derive(Debug)]
pub struct Loop;
impl NonConstOp for Loop {
fn feature_gate() -> Option<Symbol> {
Some(sym::const_loop)
}

fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
// This should be caught by the HIR const-checker.
ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
}
}

#[derive(Debug)]
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
Expand Down
57 changes: 1 addition & 56 deletions src/librustc_mir/transform/check_consts/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,6 @@ impl Validator<'mir, 'tcx> {
}
}

check_short_circuiting_in_const_local(self.ccx);

if body.is_cfg_cyclic() {
// We can't provide a good span for the error here, but this should be caught by the
// HIR const-checker anyways.
self.check_op_spanned(ops::Loop, body.span);
}

self.visit_body(&body);

// Ensure that the end result is `Sync` in a non-thread local `static`.
Expand Down Expand Up @@ -483,21 +475,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
self.super_statement(statement, location);
}

StatementKind::FakeRead(
FakeReadCause::ForMatchedPlace
| FakeReadCause::ForMatchGuard
| FakeReadCause::ForGuardBinding,
_,
) => {
self.super_statement(statement, location);
self.check_op(ops::IfOrMatch);
}
StatementKind::LlvmInlineAsm { .. } => {
self.super_statement(statement, location);
self.check_op(ops::InlineAsm);
}

StatementKind::FakeRead(FakeReadCause::ForLet | FakeReadCause::ForIndex, _)
StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag { .. }
Expand Down Expand Up @@ -626,44 +609,6 @@ fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>)
.emit();
}

fn check_short_circuiting_in_const_local(ccx: &ConstCx<'_, 'tcx>) {
let body = ccx.body;

if body.control_flow_destroyed.is_empty() {
return;
}

let mut locals = body.vars_iter();
if let Some(local) = locals.next() {
let span = body.local_decls[local].source_info.span;
let mut error = ccx.tcx.sess.struct_span_err(
span,
&format!(
"new features like let bindings are not permitted in {}s \
which also use short circuiting operators",
ccx.const_kind(),
),
);
for (span, kind) in body.control_flow_destroyed.iter() {
error.span_note(
*span,
&format!(
"use of {} here does not actually short circuit due to \
the const evaluator presently not being able to do control flow. \
See issue #49146 <https://github.com/rust-lang/rust/issues/49146> \
for more information.",
kind
),
);
}
for local in locals {
let span = body.local_decls[local].source_info.span;
error.span_note(span, "more locals are defined here");
}
error.emit();
}
}

fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
let ty = body.return_ty();
tcx.infer_ctxt().enter(|infcx| {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
body.arg_count,
Default::default(),
tcx.def_span(source.def_id()),
Default::default(),
body.generator_kind,
);

Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,6 @@ pub fn promote_candidates<'tcx>(
0,
vec![],
body.span,
vec![],
body.generator_kind,
);
promoted.ignore_interior_mut_in_const_validation = true;
Expand Down
10 changes: 0 additions & 10 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,6 @@ fn check_statement(
check_rvalue(tcx, body, def_id, rval, span)
}

StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
if !feature_allowed(tcx, def_id, sym::const_if_match) =>
{
Err((span, "loops and conditional expressions are not stable in const fn".into()))
}

StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body),

// just an assignment
Expand Down Expand Up @@ -355,10 +349,6 @@ fn check_terminator(
check_operand(tcx, value, span, def_id, body)
}

TerminatorKind::SwitchInt { .. } if !feature_allowed(tcx, def_id, sym::const_if_match) => {
Err((span, "loops and conditional expressions are not stable in const fn".into()))
}

TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
check_operand(tcx, discr, span, def_id, body)
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir_build/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.arg_count,
self.var_debug_info,
self.fn_span,
self.hir.control_flow_destroyed(),
self.generator_kind,
)
}
Expand Down
14 changes: 0 additions & 14 deletions src/librustc_mir_build/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,20 +255,6 @@ fn make_mirror_unadjusted<'a, 'tcx>(
} else {
// FIXME overflow
match (op.node, cx.constness) {
// 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()));
ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
}
(hir::BinOpKind::Or, hir::Constness::Const)
if !cx.tcx.features().const_if_match =>
{
cx.control_flow_destroyed.push((op.span, "`||` operator".into()));
ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
}

(hir::BinOpKind::And, _) => ExprKind::LogicalOp {
op: LogicalOp::And,
lhs: lhs.to_ref(),
Expand Down
Loading

0 comments on commit c091c5d

Please sign in to comment.