mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Reject const closures outside const contexts
This commit is contained in:
@@ -1062,7 +1062,7 @@ fn lower_expr_closure(
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
constness: Const,
|
||||
mut constness: Const,
|
||||
movability: Movability,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
@@ -1072,11 +1072,18 @@ fn lower_expr_closure(
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
if !self.is_in_const_context {
|
||||
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
|
||||
constness = Const::No;
|
||||
}
|
||||
}
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
|
||||
// FIXME(contracts): Support contracts on closures?
|
||||
let body_id = this.lower_fn_body(decl, None, |this| {
|
||||
let body_id = this.lower_fn_body(decl, None, constness, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::mem;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
@@ -345,6 +347,7 @@ fn lower_item_kind(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
header.constness,
|
||||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
@@ -1024,6 +1027,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
Some(body),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1217,6 +1221,7 @@ fn lower_impl_item(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1346,11 +1351,13 @@ pub(super) fn lower_body(
|
||||
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
|
||||
) -> hir::BodyId {
|
||||
let prev_coroutine_kind = self.coroutine_kind.take();
|
||||
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
|
||||
let task_context = self.task_context.take();
|
||||
let (parameters, result) = f(self);
|
||||
let body_id = self.record_body(parameters, result);
|
||||
self.task_context = task_context;
|
||||
self.coroutine_kind = prev_coroutine_kind;
|
||||
self.is_in_const_context = prev_is_in_const_context;
|
||||
body_id
|
||||
}
|
||||
|
||||
@@ -1369,9 +1376,13 @@ pub(super) fn lower_fn_body(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
self.lower_body(|this| {
|
||||
if let Const::Yes(_) = constness {
|
||||
this.is_in_const_context = true;
|
||||
}
|
||||
let params =
|
||||
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
|
||||
|
||||
@@ -1389,8 +1400,9 @@ fn lower_fn_body_block(
|
||||
decl: &FnDecl,
|
||||
body: &Block,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
|
||||
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
|
||||
}
|
||||
|
||||
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
|
||||
@@ -1398,7 +1410,10 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi
|
||||
(
|
||||
&[],
|
||||
match expr {
|
||||
Some(expr) => this.lower_expr_mut(expr),
|
||||
Some(expr) => {
|
||||
this.is_in_const_context = true;
|
||||
this.lower_expr_mut(expr)
|
||||
}
|
||||
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
|
||||
},
|
||||
)
|
||||
@@ -1417,12 +1432,13 @@ fn lower_maybe_coroutine_body(
|
||||
body: Option<&Block>,
|
||||
attrs: &'hir [hir::Attribute],
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
let Some(body) = body else {
|
||||
// Functions without a body are an error, except if this is an intrinsic. For those we
|
||||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||
// this as a special case.
|
||||
return self.lower_fn_body(decl, contract, |this| {
|
||||
return self.lower_fn_body(decl, contract, constness, |this| {
|
||||
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
|
||||
let span = this.lower_span(span);
|
||||
let empty_block = hir::Block {
|
||||
@@ -1447,7 +1463,7 @@ fn lower_maybe_coroutine_body(
|
||||
};
|
||||
let Some(coroutine_kind) = coroutine_kind else {
|
||||
// Typical case: not a coroutine.
|
||||
return self.lower_fn_body_block(decl, body, contract);
|
||||
return self.lower_fn_body_block(decl, body, contract, constness);
|
||||
};
|
||||
// FIXME(contracts): Support contracts on async fn.
|
||||
self.lower_body(|this| {
|
||||
|
||||
@@ -129,6 +129,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
loop_scope: Option<HirId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_dyn_type: bool,
|
||||
is_in_const_context: bool,
|
||||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
@@ -190,6 +191,7 @@ fn new(
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_dyn_type: false,
|
||||
is_in_const_context: false,
|
||||
coroutine_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = create_array(const |i| 2 * i as u32);
|
||||
let x = const { create_array(const |i| 2 * i as u32) };
|
||||
assert_eq!(x, [0, 2, 4, 6, 8]);
|
||||
|
||||
let y = create_array(const |i| 2 * i as u32 + 1);
|
||||
let y = const { create_array(const |i| 2 * i as u32 + 1) };
|
||||
assert_eq!(y, [1, 3, 5, 7, 9]);
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//@ check-pass
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
|
||||
const fn create_array<const N: usize>(mut f: impl [const] FnMut(usize) -> u32 + Copy) -> [u32; N] {
|
||||
let mut array = [0; N];
|
||||
let mut i = 0;
|
||||
loop {
|
||||
array[i] = f(i);
|
||||
i += 1;
|
||||
if i == N {
|
||||
break;
|
||||
}
|
||||
}
|
||||
array
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = create_array(const |i| 2 * i as u32);
|
||||
assert_eq!(x, [0, 2, 4, 6, 8]);
|
||||
|
||||
let y = create_array(const |i| 2 * i as u32 + 1);
|
||||
assert_eq!(y, [1, 3, 5, 7, 9]);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5
|
||||
error: cannot use `const` closures outside of const contexts
|
||||
--> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:6
|
||||
|
|
||||
LL | (const || (()).foo())();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// gate-test-const_closures
|
||||
|
||||
fn main() {
|
||||
(const || {})();
|
||||
const { (const || {})() };
|
||||
//~^ ERROR: const closures are experimental
|
||||
//~| ERROR: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied
|
||||
//~| ERROR: the trait bound `{closure@$DIR/gate.rs:4:14: 4:22}: [const] Fn()` is not satisfied
|
||||
}
|
||||
|
||||
macro_rules! e {
|
||||
($e:expr) => {}
|
||||
($e:expr) => {};
|
||||
}
|
||||
|
||||
e!((const || {}));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0658]: const closures are experimental
|
||||
--> $DIR/gate.rs:4:6
|
||||
--> $DIR/gate.rs:4:14
|
||||
|
|
||||
LL | (const || {})();
|
||||
| ^^^^^
|
||||
LL | const { (const || {})() };
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information
|
||||
= help: add `#![feature(const_closures)]` to the crate attributes to enable
|
||||
@@ -18,11 +18,11 @@ LL | e!((const || {}));
|
||||
= help: add `#![feature(const_closures)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0277]: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/gate.rs:4:5
|
||||
error[E0277]: the trait bound `{closure@$DIR/gate.rs:4:14: 4:22}: [const] Fn()` is not satisfied
|
||||
--> $DIR/gate.rs:4:13
|
||||
|
|
||||
LL | (const || {})();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | const { (const || {})() };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
||||
@@ -13,5 +13,5 @@ fn main() {
|
||||
// #150052 deduplicate diagnostics for const trait supertraits
|
||||
// so we only get one error here
|
||||
(const || { (()).foo() })();
|
||||
//~^ ERROR: }: [const] Fn()` is not satisfied
|
||||
//~^ ERROR: cannot use `const` closures outside of const contexts
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5
|
||||
error: cannot use `const` closures outside of const contexts
|
||||
--> $DIR/non-const-op-const-closure-non-const-outer.rs:15:6
|
||||
|
|
||||
LL | (const || { (()).foo() })();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
Reference in New Issue
Block a user