Skip to content

Commit

Permalink
Auto merge of rust-lang#87237 - jonas-schievink:const-for-and-try, r=…
Browse files Browse the repository at this point in the history
…oli-obk

Add feature gates for `for` and `?` in consts

These operations seems *relatively* straightforward to support, and only seem to be blocked on `impl const Trait`.

I have included a working test for `const_try`, but `const_for` is currently unusable without reimplementing *every single* defaulted `Iterator` method, so I didn't do that.

(both features still need tracking issues before this is merged)
  • Loading branch information
bors committed Jul 30, 2021
2 parents 1195bea + c5a29f9 commit 87dc824
Show file tree
Hide file tree
Showing 19 changed files with 162 additions and 34 deletions.
18 changes: 4 additions & 14 deletions compiler/rustc_error_codes/src/error_codes/E0744.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@ An unsupported expression was used inside a const context.

Erroneous code example:

```compile_fail,E0744
```compile_fail,edition2018,E0744
const _: i32 = {
let mut x = 0;
for i in 0..4 { // error!
x += i;
}
async { 0 }.await
};
```

At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden
inside a `const`, `static`, or `const fn`.
At the moment, `.await` is forbidden inside a `const`, `static`, or `const fn`.

This may be allowed at some point in the future, but the implementation is not
yet complete. See the tracking issues for [`async`] and [`?`] in `const fn`, and
(to support `for` loops in `const fn`) the tracking issues for [`impl const
Trait for Ty`] and [`&mut T`] in `const fn`.
yet complete. See the tracking issue for [`async`] in `const fn`.

[`async`]: https://github.com/rust-lang/rust/issues/69431
[`?`]: https://github.com/rust-lang/rust/issues/74935
[`impl const Trait for Ty`]: https://github.com/rust-lang/rust/issues/67792
[`&mut T`]: https://github.com/rust-lang/rust/issues/57349
6 changes: 6 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,12 @@ declare_features! (
/// Allows `#[derive(Default)]` and `#[default]` on enums.
(active, derive_default_enum, "1.56.0", Some(86985), None),

/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),

/// Allows the `?` operator in const contexts.
(active, const_try, "1.56.0", Some(74935), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_passes/src/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ impl NonConstExpr {
use hir::MatchSource::*;

let gates: &[_] = match self {
// A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
// so they are not yet allowed.
// Likewise, `?` desugars to a call to `Try::into_result`.
Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
Self::Match(AwaitDesugar) => {
return None;
}

Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for],

Self::Match(TryDesugar) => &[sym::const_try],

Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),

// All other expressions are allowed.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ symbols! {
const_fn_transmute,
const_fn_union,
const_fn_unsize,
const_for,
const_format_args,
const_generic_defaults,
const_generics,
Expand All @@ -432,6 +433,7 @@ symbols! {
const_trait_bound_opt_out,
const_trait_impl,
const_transmute,
const_try,
constant,
constructor,
contents,
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-fn-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const fn f(x: usize) -> usize {
//~| ERROR calls in constant functions
//~| ERROR calls in constant functions
//~| ERROR E0080
//~| ERROR E0744
//~| ERROR `for` is not allowed in a `const fn`
sum += i;
}
sum
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/consts/const-fn-error.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0744]: `for` is not allowed in a `const fn`
error[E0658]: `for` is not allowed in a `const fn`
--> $DIR/const-fn-error.rs:5:5
|
LL | / for i in 0..x {
Expand All @@ -9,6 +9,9 @@ LL | |
LL | | sum += i;
LL | | }
| |_____^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-fn-error.rs:5:14
Expand Down Expand Up @@ -45,5 +48,5 @@ LL | let a : [i32; f(X)];

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0015, E0080, E0658, E0744.
Some errors have detailed explanations: E0015, E0080, E0658.
For more information about an error, try `rustc --explain E0015`.
8 changes: 8 additions & 0 deletions src/test/ui/consts/const-for-feature-gate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// gate-test-const_for

const _: () = {
for _ in 0..5 {}
//~^ error: `for` is not allowed in a `const`
};

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/consts/const-for-feature-gate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0658]: `for` is not allowed in a `const`
--> $DIR/const-for-feature-gate.rs:4:5
|
LL | for _ in 0..5 {}
| ^^^^^^^^^^^^^^^^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
10 changes: 10 additions & 0 deletions src/test/ui/consts/const-for.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(const_for)]
#![feature(const_mut_refs)]

const _: () = {
for _ in 0..5 {}
//~^ error: calls in constants are limited to
//~| error: calls in constants are limited to
};

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/consts/const-for.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-for.rs:5:14
|
LL | for _ in 0..5 {}
| ^^^^

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-for.rs:5:14
|
LL | for _ in 0..5 {}
| ^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
9 changes: 9 additions & 0 deletions src/test/ui/consts/const-try-feature-gate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// gate-test-const_try

const fn t() -> Option<()> {
Some(())?;
//~^ error: `?` is not allowed in a `const fn`
None
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/consts/const-try-feature-gate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0658]: `?` is not allowed in a `const fn`
--> $DIR/const-try-feature-gate.rs:4:5
|
LL | Some(())?;
| ^^^^^^^^^
|
= note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information
= help: add `#![feature(const_try)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
39 changes: 39 additions & 0 deletions src/test/ui/consts/const-try.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// check-pass

// Demonstrates what's needed to make use of `?` in const contexts.

#![crate_type = "lib"]
#![feature(try_trait_v2)]
#![feature(const_trait_impl)]
#![feature(const_try)]

use std::ops::{ControlFlow, FromResidual, Try};

struct TryMe;
struct Error;

impl const FromResidual<Error> for TryMe {
fn from_residual(residual: Error) -> Self {
TryMe
}
}

impl const Try for TryMe {
type Output = ();
type Residual = Error;
fn from_output(output: Self::Output) -> Self {
TryMe
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
ControlFlow::Break(Error)
}
}

const fn t() -> TryMe {
TryMe?;
TryMe
}

const _: () = {
t();
};
12 changes: 9 additions & 3 deletions src/test/ui/consts/control-flow/loop.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
error[E0744]: `for` is not allowed in a `const`
error[E0658]: `for` is not allowed in a `const`
--> $DIR/loop.rs:53:5
|
LL | / for i in 0..4 {
LL | | x += i;
LL | | }
| |_____^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error[E0744]: `for` is not allowed in a `const`
error[E0658]: `for` is not allowed in a `const`
--> $DIR/loop.rs:57:5
|
LL | / for i in 0..4 {
LL | | x += i;
LL | | }
| |_____^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` 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`.
7 changes: 5 additions & 2 deletions src/test/ui/consts/control-flow/try.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
error[E0744]: `?` is not allowed in a `const fn`
error[E0658]: `?` is not allowed in a `const fn`
--> $DIR/try.rs:6:5
|
LL | x?;
| ^^
|
= note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information
= help: add `#![feature(const_try)]` to the crate attributes to enable

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`.
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-50582.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error[E0744]: `for` is not allowed in a `const`
error[E0658]: `for` is not allowed in a `const`
--> $DIR/issue-50582.rs:2:20
|
LL | Vec::<[(); 1 + for x in 0..1 {}]>::new();
| ^^^^^^^^^^^^^^^^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error[E0277]: cannot add `()` to `{integer}`
--> $DIR/issue-50582.rs:2:18
Expand All @@ -14,5 +17,5 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new();

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0744.
Some errors have detailed explanations: E0277, E0658.
For more information about an error, try `rustc --explain E0277`.
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-50585.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error[E0744]: `for` is not allowed in a `const`
error[E0658]: `for` is not allowed in a `const`
--> $DIR/issue-50585.rs:2:18
|
LL | |y: Vec<[(); for x in 0..2 {}]>| {};
| ^^^^^^^^^^^^^^^^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error[E0308]: mismatched types
--> $DIR/issue-50585.rs:2:18
Expand All @@ -12,5 +15,5 @@ LL | |y: Vec<[(); for x in 0..2 {}]>| {};

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0308, E0744.
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
7 changes: 5 additions & 2 deletions src/test/ui/never_type/issue-52443.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ LL | [(); {while true {break}; 0}];
|
= note: `#[warn(while_true)]` on by default

error[E0744]: `for` is not allowed in a `const`
error[E0658]: `for` is not allowed in a `const`
--> $DIR/issue-52443.rs:9:12
|
LL | [(); { for _ in 0usize.. {}; 0}];
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
= help: add `#![feature(const_for)]` to the crate attributes to enable

error[E0308]: mismatched types
--> $DIR/issue-52443.rs:2:10
Expand Down Expand Up @@ -56,5 +59,5 @@ LL | [(); { for _ in 0usize.. {}; 0}];

error: aborting due to 6 previous errors; 1 warning emitted

Some errors have detailed explanations: E0015, E0308, E0658, E0744.
Some errors have detailed explanations: E0015, E0308, E0658.
For more information about an error, try `rustc --explain E0015`.
7 changes: 5 additions & 2 deletions src/test/ui/rfc-2632-const-trait-impl/hir-const-check.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
error[E0744]: `?` is not allowed in a `const fn`
error[E0658]: `?` is not allowed in a `const fn`
--> $DIR/hir-const-check.rs:11:9
|
LL | Some(())?;
| ^^^^^^^^^
|
= note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information
= help: add `#![feature(const_try)]` to the crate attributes to enable

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

0 comments on commit 87dc824

Please sign in to comment.