Skip to content

Commit 415454f

Browse files
committed
Check closure's constness validity in the constness query
instead of during ast lowering, where it's not easily possible to obtain all the right information in time
1 parent 090b2a9 commit 415454f

12 files changed

Lines changed: 33 additions & 70 deletions

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
10521052
binder: &ClosureBinder,
10531053
capture_clause: CaptureBy,
10541054
closure_id: NodeId,
1055-
mut constness: Const,
1055+
constness: Const,
10561056
movability: Movability,
10571057
decl: &FnDecl,
10581058
body: &Expr,
@@ -1062,18 +1062,11 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
10621062
let closure_def_id = self.local_def_id(closure_id);
10631063
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
10641064

1065-
if let Const::Yes(span) = constness {
1066-
if !self.is_in_const_context {
1067-
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
1068-
constness = Const::No;
1069-
}
1070-
}
1071-
10721065
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
10731066
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
10741067

10751068
// FIXME(contracts): Support contracts on closures?
1076-
let body_id = this.lower_fn_body(decl, None, constness, |this| {
1069+
let body_id = this.lower_fn_body(decl, None, |this| {
10771070
this.coroutine_kind = coroutine_kind;
10781071
let e = this.lower_expr_mut(body);
10791072
coroutine_kind = this.coroutine_kind;

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::mem;
21
use std::sync::Arc;
32

43
use rustc_abi::ExternAbi;
@@ -391,7 +390,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
391390
body.as_deref(),
392391
attrs,
393392
contract.as_deref(),
394-
header.constness,
395393
);
396394

397395
let itctx = ImplTraitContext::Universal;
@@ -1081,7 +1079,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
10811079
Some(body),
10821080
attrs,
10831081
contract.as_deref(),
1084-
sig.header.constness,
10851082
);
10861083
let (generics, sig) = self.lower_method_sig(
10871084
generics,
@@ -1275,7 +1272,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
12751272
body.as_deref(),
12761273
attrs,
12771274
contract.as_deref(),
1278-
sig.header.constness,
12791275
);
12801276
let (generics, sig) = self.lower_method_sig(
12811277
generics,
@@ -1405,13 +1401,11 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
14051401
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
14061402
) -> hir::BodyId {
14071403
let prev_coroutine_kind = self.coroutine_kind.take();
1408-
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
14091404
let task_context = self.task_context.take();
14101405
let (parameters, result) = f(self);
14111406
let body_id = self.record_body(parameters, result);
14121407
self.task_context = task_context;
14131408
self.coroutine_kind = prev_coroutine_kind;
1414-
self.is_in_const_context = prev_is_in_const_context;
14151409
body_id
14161410
}
14171411

@@ -1430,13 +1424,9 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
14301424
&mut self,
14311425
decl: &FnDecl,
14321426
contract: Option<&FnContract>,
1433-
constness: Const,
14341427
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
14351428
) -> hir::BodyId {
14361429
self.lower_body(|this| {
1437-
if let Const::Yes(_) = constness {
1438-
this.is_in_const_context = true;
1439-
}
14401430
let params =
14411431
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
14421432

@@ -1454,20 +1444,16 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
14541444
decl: &FnDecl,
14551445
body: &Block,
14561446
contract: Option<&FnContract>,
1457-
constness: Const,
14581447
) -> hir::BodyId {
1459-
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
1448+
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
14601449
}
14611450

14621451
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
14631452
self.lower_body(|this| {
14641453
(
14651454
&[],
14661455
match expr {
1467-
Some(expr) => {
1468-
this.is_in_const_context = true;
1469-
this.lower_expr_mut(expr)
1470-
}
1456+
Some(expr) => this.lower_expr_mut(expr),
14711457
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
14721458
},
14731459
)
@@ -1486,13 +1472,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
14861472
body: Option<&Block>,
14871473
attrs: &'hir [hir::Attribute],
14881474
contract: Option<&FnContract>,
1489-
constness: Const,
14901475
) -> hir::BodyId {
14911476
let Some(body) = body else {
14921477
// Functions without a body are an error, except if this is an intrinsic. For those we
14931478
// create a fake body so that the entire rest of the compiler doesn't have to deal with
14941479
// this as a special case.
1495-
return self.lower_fn_body(decl, contract, constness, |this| {
1480+
return self.lower_fn_body(decl, contract, |this| {
14961481
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
14971482
let span = this.lower_span(span);
14981483
let empty_block = hir::Block {
@@ -1517,7 +1502,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
15171502
};
15181503
let Some(coroutine_kind) = coroutine_kind else {
15191504
// Typical case: not a coroutine.
1520-
return self.lower_fn_body_block(decl, body, contract, constness);
1505+
return self.lower_fn_body_block(decl, body, contract);
15211506
};
15221507
// FIXME(contracts): Support contracts on async fn.
15231508
self.lower_body(|this| {

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ struct LoweringContext<'a, 'hir, R> {
125125
loop_scope: Option<HirId>,
126126
is_in_loop_condition: bool,
127127
is_in_dyn_type: bool,
128-
is_in_const_context: bool,
129128

130129
current_hir_id_owner: hir::OwnerId,
131130
item_local_id_counter: hir::ItemLocalId,
@@ -182,7 +181,6 @@ impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
182181
loop_scope: None,
183182
is_in_loop_condition: false,
184183
is_in_dyn_type: false,
185-
is_in_const_context: false,
186184
coroutine_kind: None,
187185
task_context: None,
188186
current_item: None,

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
1616
// Foreign functions cannot be evaluated at compile-time.
1717
Constness::NotConst
1818
}
19-
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => c.constness,
19+
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => {
20+
if let Constness::Const = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() {
21+
tcx.dcx().span_err(tcx.def_span(def_id), "cannot use `const` closures outside of const contexts");
22+
return Constness::NotConst;
23+
}
24+
c.constness
25+
},
2026
// FIXME(fee1-dead): extract this one out and rename this query to `fn_constness` so we don't need `is_const_fn` anymore.
2127
Node::Item(i) if let ItemKind::Impl(impl_) = i.kind => impl_.constness,
2228
Node::Item(Item { kind: ItemKind::Fn { sig, .. }, .. }) => sig.header.constness,

compiler/rustc_middle/src/hir/map.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,7 @@ impl<'tcx> TyCtxt<'tcx> {
319319
BodyOwnerKind::Fn if self.is_constructor(def_id) => return None,
320320
// Const closures use their parent's const context
321321
BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
322-
return Some(
323-
self.hir_body_const_context(self.local_parent(local_def_id)).unwrap_or_else(
324-
|| {
325-
assert!(
326-
self.dcx().has_errors().is_some(),
327-
"`const` closure with no enclosing const context",
328-
);
329-
ConstContext::ConstFn
330-
},
331-
),
332-
);
322+
return self.hir_body_const_context(self.local_parent(local_def_id));
333323
}
334324
BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn,
335325
BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,

tests/ui/consts/const-closure-in-trait-impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//@ check-pass
2+
13
#![feature(const_closures, const_destruct, const_trait_impl)]
24

35
use std::marker::Destruct;
@@ -17,8 +19,6 @@ impl const T for S {
1719

1820
fn b(&mut self) {
1921
self.a(const || {});
20-
//~^ ERROR: cannot use `const` closures outside of const contexts
21-
//~| ERROR: [const] Fn()` is not satisfied
2222
}
2323
}
2424

tests/ui/consts/const-closure-in-trait-impl.stderr

Lines changed: 0 additions & 23 deletions
This file was deleted.

tests/ui/traits/const-traits/const-closure-in-non-const-trait-impl-method.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl<T: Foo> Foo for &mut T {
1111
const fn test() -> impl [const] Fn() {
1212
//~^ ERROR functions in trait impls cannot be declared const
1313
const move || {}
14+
//~^ ERROR: cannot use `const` closures outside of const contexts
1415
}
1516
}
1617

tests/ui/traits/const-traits/const-closure-in-non-const-trait-impl-method.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ help: ... and declare the impl to be const instead
1414
LL | impl<T: Foo> const Foo for &mut T {
1515
| +++++
1616

17-
error: aborting due to 1 previous error
17+
error: cannot use `const` closures outside of const contexts
18+
--> $DIR/const-closure-in-non-const-trait-impl-method.rs:13:9
19+
|
20+
LL | const move || {}
21+
| ^^^^^^^^^^^^^
22+
23+
error: aborting due to 2 previous errors
1824

1925
For more information about this error, try `rustc --explain E0379`.

tests/ui/traits/const-traits/const-closure-in-non-const-trait-method.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ trait Tr {
66
const fn test() {
77
//~^ ERROR functions in traits cannot be declared const
88
(const || {})()
9+
//~^ ERROR cannot use `const` closures outside of const contexts
910
}
1011
}
1112

0 commit comments

Comments
 (0)