Skip to content

Commit 279f1c9

Browse files
committed
Auto merge of #106004 - fee1-dead-contrib:const-closures, r=oli-obk
Const closures cc #106003
2 parents bfffe40 + 42a50ba commit 279f1c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+249
-48
lines changed

compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,7 @@ impl Expr {
13071307
pub struct Closure {
13081308
pub binder: ClosureBinder,
13091309
pub capture_clause: CaptureBy,
1310+
pub constness: Const,
13101311
pub asyncness: Async,
13111312
pub movability: Movability,
13121313
pub fn_decl: P<FnDecl>,

compiler/rustc_ast/src/mut_visit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
13621362
ExprKind::Closure(box Closure {
13631363
binder,
13641364
capture_clause: _,
1365+
constness,
13651366
asyncness,
13661367
movability: _,
13671368
fn_decl,
@@ -1370,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
13701371
fn_arg_span: _,
13711372
}) => {
13721373
vis.visit_closure_binder(binder);
1374+
visit_constness(constness, vis);
13731375
vis.visit_asyncness(asyncness);
13741376
vis.visit_fn_decl(fn_decl);
13751377
vis.visit_expr(body);

compiler/rustc_ast/src/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
836836
binder,
837837
capture_clause: _,
838838
asyncness: _,
839+
constness: _,
839840
movability: _,
840841
fn_decl,
841842
body,

compiler/rustc_ast_lowering/src/expr.rs

+6
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
209209
ExprKind::Closure(box Closure {
210210
binder,
211211
capture_clause,
212+
constness,
212213
asyncness,
213214
movability,
214215
fn_decl,
@@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
233234
binder,
234235
*capture_clause,
235236
e.id,
237+
*constness,
236238
*movability,
237239
fn_decl,
238240
body,
@@ -651,6 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
651653
fn_decl_span: self.lower_span(span),
652654
fn_arg_span: None,
653655
movability: Some(hir::Movability::Static),
656+
constness: hir::Constness::NotConst,
654657
});
655658

656659
hir::ExprKind::Closure(c)
@@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
890893
binder: &ClosureBinder,
891894
capture_clause: CaptureBy,
892895
closure_id: NodeId,
896+
constness: Const,
893897
movability: Movability,
894898
decl: &FnDecl,
895899
body: &Expr,
@@ -927,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
927931
fn_decl_span: self.lower_span(fn_decl_span),
928932
fn_arg_span: Some(self.lower_span(fn_arg_span)),
929933
movability: generator_option,
934+
constness: self.lower_constness(constness),
930935
});
931936

932937
hir::ExprKind::Closure(c)
@@ -1041,6 +1046,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10411046
fn_decl_span: self.lower_span(fn_decl_span),
10421047
fn_arg_span: Some(self.lower_span(fn_arg_span)),
10431048
movability: None,
1049+
constness: hir::Constness::NotConst,
10441050
});
10451051
hir::ExprKind::Closure(c)
10461052
}

compiler/rustc_ast_lowering/src/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12391239
}
12401240
}
12411241

1242-
fn lower_constness(&mut self, c: Const) -> hir::Constness {
1242+
pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
12431243
match c {
12441244
Const::Yes(_) => hir::Constness::Const,
12451245
Const::No => hir::Constness::NotConst,

compiler/rustc_ast_passes/src/feature_gate.rs

+8
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
385385
ast::ExprKind::TryBlock(_) => {
386386
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
387387
}
388+
ast::ExprKind::Closure(box ast::Closure { constness: ast::Const::Yes(_), .. }) => {
389+
gate_feature_post!(
390+
&self,
391+
const_closures,
392+
e.span,
393+
"const closures are experimental"
394+
);
395+
}
388396
_ => {}
389397
}
390398
visit::walk_expr(self, e)

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ impl<'a> State<'a> {
399399
ast::ExprKind::Closure(box ast::Closure {
400400
binder,
401401
capture_clause,
402+
constness,
402403
asyncness,
403404
movability,
404405
fn_decl,
@@ -407,6 +408,7 @@ impl<'a> State<'a> {
407408
fn_arg_span: _,
408409
}) => {
409410
self.print_closure_binder(binder);
411+
self.print_constness(*constness);
410412
self.print_movability(*movability);
411413
self.print_asyncness(*asyncness);
412414
self.print_capture_clause(*capture_clause);

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
4141
};
4242
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
4343
}
44+
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
4445
_ => {
4546
if let Some(fn_kind) = node.fn_kind() {
4647
if fn_kind.constness() == hir::Constness::Const {

compiler/rustc_const_eval/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust.
2020
#![feature(trusted_step)]
2121
#![feature(try_blocks)]
2222
#![feature(yeet_expr)]
23+
#![feature(if_let_guard)]
2324
#![feature(is_some_and)]
2425
#![recursion_limit = "256"]
2526

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
242242
// impl trait is gone in MIR, so check the return type of a const fn by its signature
243243
// instead of the type of the return place.
244244
self.span = body.local_decls[RETURN_PLACE].source_info.span;
245-
let return_ty = tcx.fn_sig(def_id).output();
245+
let return_ty = self.ccx.fn_sig().output();
246246
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
247247
}
248248

@@ -730,6 +730,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
730730
substs,
731731
span: *fn_span,
732732
from_hir_call: *from_hir_call,
733+
feature: Some(sym::const_trait_impl),
733734
});
734735
return;
735736
}
@@ -782,6 +783,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
782783
);
783784
return;
784785
}
786+
Ok(Some(ImplSource::Closure(data))) => {
787+
if !tcx.is_const_fn_raw(data.closure_def_id) {
788+
self.check_op(ops::FnCallNonConst {
789+
caller,
790+
callee,
791+
substs,
792+
span: *fn_span,
793+
from_hir_call: *from_hir_call,
794+
feature: None,
795+
});
796+
797+
return;
798+
}
799+
}
785800
Ok(Some(ImplSource::UserDefined(data))) => {
786801
let callee_name = tcx.item_name(callee);
787802
if let Some(&did) = tcx
@@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
802817
substs,
803818
span: *fn_span,
804819
from_hir_call: *from_hir_call,
820+
feature: None,
805821
});
806822
return;
807823
}
@@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
844860
substs,
845861
span: *fn_span,
846862
from_hir_call: *from_hir_call,
863+
feature: None,
847864
});
848865
return;
849866
}
@@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
903920
substs,
904921
span: *fn_span,
905922
from_hir_call: *from_hir_call,
923+
feature: None,
906924
});
907925
return;
908926
}

compiler/rustc_const_eval/src/transform/check_consts/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_attr as attr;
88
use rustc_hir as hir;
99
use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_middle::mir;
11-
use rustc_middle::ty::{self, TyCtxt};
11+
use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
1212
use rustc_span::Symbol;
1313

1414
pub use self::qualifs::Qualif;
@@ -64,6 +64,17 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
6464
fn is_async(&self) -> bool {
6565
self.tcx.asyncness(self.def_id()).is_async()
6666
}
67+
68+
pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
69+
let did = self.def_id().to_def_id();
70+
if self.tcx.is_closure(did) {
71+
let ty = self.tcx.type_of(did);
72+
let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") };
73+
substs.as_closure().sig()
74+
} else {
75+
self.tcx.fn_sig(did)
76+
}
77+
}
6778
}
6879

6980
pub fn rustc_allow_const_fn_unstable(

compiler/rustc_const_eval/src/transform/check_consts/ops.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub struct FnCallNonConst<'tcx> {
111111
pub substs: SubstsRef<'tcx>,
112112
pub span: Span,
113113
pub from_hir_call: bool,
114+
pub feature: Option<Symbol>,
114115
}
115116

116117
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
@@ -119,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
119120
ccx: &ConstCx<'_, 'tcx>,
120121
_: Span,
121122
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
122-
let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
123+
let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
123124
let ConstCx { tcx, param_env, .. } = *ccx;
124125

125126
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@@ -318,6 +319,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
318319
ccx.const_kind(),
319320
));
320321

322+
if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
323+
err.help(&format!(
324+
"add `#![feature({})]` to the crate attributes to enable",
325+
feature,
326+
));
327+
}
328+
321329
if let ConstContext::Static(_) = ccx.const_kind() {
322330
err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
323331
}

compiler/rustc_expand/src/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ impl<'a> ExtCtxt<'a> {
533533
ast::ExprKind::Closure(Box::new(ast::Closure {
534534
binder: ast::ClosureBinder::NotPresent,
535535
capture_clause: ast::CaptureBy::Ref,
536+
constness: ast::Const::No,
536537
asyncness: ast::Async::No,
537538
movability: ast::Movability::Movable,
538539
fn_decl,

compiler/rustc_feature/src/active.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ declare_features! (
339339
(active, collapse_debuginfo, "1.65.0", Some(100758), None),
340340
/// Allows `async {}` expressions in const contexts.
341341
(active, const_async_blocks, "1.53.0", Some(85368), None),
342-
// Allows limiting the evaluation steps of const expressions
342+
/// Allows `const || {}` closures in const contexts.
343+
(incomplete, const_closures, "CURRENT_RUSTC_VERSION", Some(106003), None),
344+
/// Allows limiting the evaluation steps of const expressions
343345
(active, const_eval_limit, "1.43.0", Some(67217), None),
344346
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
345347
(active, const_extern_fn, "1.40.0", Some(64926), None),

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,7 @@ pub struct Crate<'hir> {
938938
pub struct Closure<'hir> {
939939
pub def_id: LocalDefId,
940940
pub binder: ClosureBinder,
941+
pub constness: Constness,
941942
pub capture_clause: CaptureBy,
942943
pub bound_generic_params: &'hir [GenericParam<'hir>],
943944
pub fn_decl: &'hir FnDecl<'hir>,

compiler/rustc_hir/src/intravisit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
742742
fn_decl_span: _,
743743
fn_arg_span: _,
744744
movability: _,
745+
constness: _,
745746
}) => {
746747
walk_list!(visitor, visit_generic_param, bound_generic_params);
747748
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)

compiler/rustc_hir_pretty/src/lib.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,7 @@ impl<'a> State<'a> {
14641464
}
14651465
hir::ExprKind::Closure(&hir::Closure {
14661466
binder,
1467+
constness,
14671468
capture_clause,
14681469
bound_generic_params,
14691470
fn_decl,
@@ -1474,6 +1475,7 @@ impl<'a> State<'a> {
14741475
def_id: _,
14751476
}) => {
14761477
self.print_closure_binder(binder, bound_generic_params);
1478+
self.print_constness(constness);
14771479
self.print_capture_clause(capture_clause);
14781480

14791481
self.print_closure_params(fn_decl, body);
@@ -2272,10 +2274,7 @@ impl<'a> State<'a> {
22722274
}
22732275

22742276
pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
2275-
match header.constness {
2276-
hir::Constness::NotConst => {}
2277-
hir::Constness::Const => self.word_nbsp("const"),
2278-
}
2277+
self.print_constness(header.constness);
22792278

22802279
match header.asyncness {
22812280
hir::IsAsync::NotAsync => {}
@@ -2292,6 +2291,13 @@ impl<'a> State<'a> {
22922291
self.word("fn")
22932292
}
22942293

2294+
pub fn print_constness(&mut self, s: hir::Constness) {
2295+
match s {
2296+
hir::Constness::NotConst => {}
2297+
hir::Constness::Const => self.word_nbsp("const"),
2298+
}
2299+
}
2300+
22952301
pub fn print_unsafety(&mut self, s: hir::Unsafety) {
22962302
match s {
22972303
hir::Unsafety::Normal => {}

compiler/rustc_metadata/src/rmeta/encoder.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16861686
}
16871687

16881688
ty::Closure(_, substs) => {
1689+
let constness = self.tcx.constness(def_id.to_def_id());
1690+
self.tables.constness.set(def_id.to_def_id().index, constness);
16891691
record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig());
16901692
}
16911693

compiler/rustc_middle/src/hir/map/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,9 @@ impl<'hir> Map<'hir> {
485485
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
486486

487487
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
488-
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
488+
BodyOwnerKind::Fn | BodyOwnerKind::Closure
489+
if self.tcx.is_const_fn_raw(def_id.to_def_id()) =>
490+
{
489491
ConstContext::ConstFn
490492
}
491493
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {

compiler/rustc_middle/src/traits/select.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ pub enum SelectionCandidate<'tcx> {
131131

132132
/// Implementation of a `Fn`-family trait by one of the anonymous types
133133
/// generated for an `||` expression.
134-
ClosureCandidate,
134+
ClosureCandidate {
135+
is_const: bool,
136+
},
135137

136138
/// Implementation of a `Generator` trait by one of the anonymous types
137139
/// generated for a generator.

compiler/rustc_middle/src/ty/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2465,8 +2465,10 @@ impl<'tcx> TyCtxt<'tcx> {
24652465

24662466
#[inline]
24672467
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
2468-
matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
2469-
&& self.constness(def_id) == hir::Constness::Const
2468+
matches!(
2469+
self.def_kind(def_id),
2470+
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
2471+
) && self.constness(def_id) == hir::Constness::Const
24702472
}
24712473

24722474
#[inline]

0 commit comments

Comments
 (0)