1
Fork 0

Auto merge of #87237 - jonas-schievink:const-for-and-try, r=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)
This commit is contained in:
bors 2021-07-30 12:05:48 +00:00
commit 87dc824248
19 changed files with 162 additions and 34 deletions

View file

@ -2,25 +2,15 @@ An unsupported expression was used inside a const context.
Erroneous code example: Erroneous code example:
```compile_fail,E0744 ```compile_fail,edition2018,E0744
const _: i32 = { const _: i32 = {
let mut x = 0; async { 0 }.await
for i in 0..4 { // error!
x += i;
}
}; };
``` ```
At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden At the moment, `.await` is forbidden inside a `const`, `static`, or `const fn`.
inside a `const`, `static`, or `const fn`.
This may be allowed at some point in the future, but the implementation is not 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 yet complete. See the tracking issue for [`async`] in `const fn`.
(to support `for` loops in `const fn`) the tracking issues for [`impl const
Trait for Ty`] and [`&mut T`] in `const fn`.
[`async`]: https://github.com/rust-lang/rust/issues/69431 [`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

View file

@ -677,6 +677,12 @@ declare_features! (
/// Allows `#[derive(Default)]` and `#[default]` on enums. /// Allows `#[derive(Default)]` and `#[default]` on enums.
(active, derive_default_enum, "1.56.0", Some(86985), None), (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 // feature-group-end: actual feature gates
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------

View file

@ -40,13 +40,14 @@ impl NonConstExpr {
use hir::MatchSource::*; use hir::MatchSource::*;
let gates: &[_] = match self { let gates: &[_] = match self {
// A `for` loop's desugaring contains a call to `IntoIterator::into_iter`, Self::Match(AwaitDesugar) => {
// so they are not yet allowed.
// Likewise, `?` desugars to a call to `Try::into_result`.
Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
return None; 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"), Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
// All other expressions are allowed. // All other expressions are allowed.

View file

@ -410,6 +410,7 @@ symbols! {
const_fn_transmute, const_fn_transmute,
const_fn_union, const_fn_union,
const_fn_unsize, const_fn_unsize,
const_for,
const_format_args, const_format_args,
const_generic_defaults, const_generic_defaults,
const_generics, const_generics,
@ -432,6 +433,7 @@ symbols! {
const_trait_bound_opt_out, const_trait_bound_opt_out,
const_trait_impl, const_trait_impl,
const_transmute, const_transmute,
const_try,
constant, constant,
constructor, constructor,
contents, contents,

View file

@ -7,7 +7,7 @@ const fn f(x: usize) -> usize {
//~| ERROR calls in constant functions //~| ERROR calls in constant functions
//~| ERROR calls in constant functions //~| ERROR calls in constant functions
//~| ERROR E0080 //~| ERROR E0080
//~| ERROR E0744 //~| ERROR `for` is not allowed in a `const fn`
sum += i; sum += i;
} }
sum sum

View file

@ -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 --> $DIR/const-fn-error.rs:5:5
| |
LL | / for i in 0..x { LL | / for i in 0..x {
@ -9,6 +9,9 @@ LL | |
LL | | sum += i; LL | | sum += i;
LL | | } 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 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-fn-error.rs:5:14 --> $DIR/const-fn-error.rs:5:14
@ -45,5 +48,5 @@ LL | let a : [i32; f(X)];
error: aborting due to 5 previous errors 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`. For more information about an error, try `rustc --explain E0015`.

View file

@ -0,0 +1,8 @@
// gate-test-const_for
const _: () = {
for _ in 0..5 {}
//~^ error: `for` is not allowed in a `const`
};
fn main() {}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,9 @@
// gate-test-const_try
const fn t() -> Option<()> {
Some(())?;
//~^ error: `?` is not allowed in a `const fn`
None
}
fn main() {}

View file

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

View file

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

View file

@ -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 --> $DIR/loop.rs:53:5
| |
LL | / for i in 0..4 { LL | / for i in 0..4 {
LL | | x += i; LL | | x += i;
LL | | } 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 --> $DIR/loop.rs:57:5
| |
LL | / for i in 0..4 { LL | / for i in 0..4 {
LL | | x += i; LL | | x += i;
LL | | } 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 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

@ -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 --> $DIR/try.rs:6:5
| |
LL | x?; 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 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

@ -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 --> $DIR/issue-50582.rs:2:20
| |
LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); 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}` error[E0277]: cannot add `()` to `{integer}`
--> $DIR/issue-50582.rs:2:18 --> $DIR/issue-50582.rs:2:18
@ -14,5 +17,5 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new();
error: aborting due to 2 previous errors 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`. For more information about an error, try `rustc --explain E0277`.

View file

@ -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 --> $DIR/issue-50585.rs:2:18
| |
LL | |y: Vec<[(); for x in 0..2 {}]>| {}; 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 error[E0308]: mismatched types
--> $DIR/issue-50585.rs:2:18 --> $DIR/issue-50585.rs:2:18
@ -12,5 +15,5 @@ LL | |y: Vec<[(); for x in 0..2 {}]>| {};
error: aborting due to 2 previous errors 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`. For more information about an error, try `rustc --explain E0308`.

View file

@ -6,11 +6,14 @@ LL | [(); {while true {break}; 0}];
| |
= note: `#[warn(while_true)]` on by default = 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 --> $DIR/issue-52443.rs:9:12
| |
LL | [(); { for _ in 0usize.. {}; 0}]; 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 error[E0308]: mismatched types
--> $DIR/issue-52443.rs:2:10 --> $DIR/issue-52443.rs:2:10
@ -56,5 +59,5 @@ LL | [(); { for _ in 0usize.. {}; 0}];
error: aborting due to 6 previous errors; 1 warning emitted 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`. For more information about an error, try `rustc --explain E0015`.

View file

@ -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 --> $DIR/hir-const-check.rs:11:9
| |
LL | Some(())?; 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 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`.