Skip to content

Commit

Permalink
Auto merge of rust-lang#106004 - fee1-dead-contrib:const-closures, r=…
Browse files Browse the repository at this point in the history
…oli-obk

Const closures

cc rust-lang#106003
  • Loading branch information
bors committed Jan 13, 2023
2 parents bfffe40 + 42a50ba commit 279f1c9
Show file tree
Hide file tree
Showing 56 changed files with 249 additions and 48 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,7 @@ impl Expr {
pub struct Closure {
pub binder: ClosureBinder,
pub capture_clause: CaptureBy,
pub constness: Const,
pub asyncness: Async,
pub movability: Movability,
pub fn_decl: P<FnDecl>,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Closure(box Closure {
binder,
capture_clause: _,
constness,
asyncness,
movability: _,
fn_decl,
Expand All @@ -1370,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
fn_arg_span: _,
}) => {
vis.visit_closure_binder(binder);
visit_constness(constness, vis);
vis.visit_asyncness(asyncness);
vis.visit_fn_decl(fn_decl);
vis.visit_expr(body);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
binder,
capture_clause: _,
asyncness: _,
constness: _,
movability: _,
fn_decl,
body,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Closure(box Closure {
binder,
capture_clause,
constness,
asyncness,
movability,
fn_decl,
Expand All @@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder,
*capture_clause,
e.id,
*constness,
*movability,
fn_decl,
body,
Expand Down Expand Up @@ -651,6 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(span),
fn_arg_span: None,
movability: Some(hir::Movability::Static),
constness: hir::Constness::NotConst,
});

hir::ExprKind::Closure(c)
Expand Down Expand Up @@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
constness: Const,
movability: Movability,
decl: &FnDecl,
body: &Expr,
Expand Down Expand Up @@ -927,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: generator_option,
constness: self.lower_constness(constness),
});

hir::ExprKind::Closure(c)
Expand Down Expand Up @@ -1041,6 +1046,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: None,
constness: hir::Constness::NotConst,
});
hir::ExprKind::Closure(c)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

fn lower_constness(&mut self, c: Const) -> hir::Constness {
pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
match c {
Const::Yes(_) => hir::Constness::Const,
Const::No => hir::Constness::NotConst,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
ast::ExprKind::Closure(box ast::Closure { constness: ast::Const::Yes(_), .. }) => {
gate_feature_post!(
&self,
const_closures,
e.span,
"const closures are experimental"
);
}
_ => {}
}
visit::walk_expr(self, e)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ impl<'a> State<'a> {
ast::ExprKind::Closure(box ast::Closure {
binder,
capture_clause,
constness,
asyncness,
movability,
fn_decl,
Expand All @@ -407,6 +408,7 @@ impl<'a> State<'a> {
fn_arg_span: _,
}) => {
self.print_closure_binder(binder);
self.print_constness(*constness);
self.print_movability(*movability);
self.print_asyncness(*asyncness);
self.print_capture_clause(*capture_clause);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
};
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
}
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
_ => {
if let Some(fn_kind) = node.fn_kind() {
if fn_kind.constness() == hir::Constness::Const {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![feature(if_let_guard)]
#![feature(is_some_and)]
#![recursion_limit = "256"]

Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
// impl trait is gone in MIR, so check the return type of a const fn by its signature
// instead of the type of the return place.
self.span = body.local_decls[RETURN_PLACE].source_info.span;
let return_ty = tcx.fn_sig(def_id).output();
let return_ty = self.ccx.fn_sig().output();
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
}

Expand Down Expand Up @@ -730,6 +730,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: Some(sym::const_trait_impl),
});
return;
}
Expand Down Expand Up @@ -782,6 +783,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
);
return;
}
Ok(Some(ImplSource::Closure(data))) => {
if !tcx.is_const_fn_raw(data.closure_def_id) {
self.check_op(ops::FnCallNonConst {
caller,
callee,
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});

return;
}
}
Ok(Some(ImplSource::UserDefined(data))) => {
let callee_name = tcx.item_name(callee);
if let Some(&did) = tcx
Expand All @@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}
Expand Down Expand Up @@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}
Expand Down Expand Up @@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_const_eval/src/transform/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
use rustc_span::Symbol;

pub use self::qualifs::Qualif;
Expand Down Expand Up @@ -64,6 +64,17 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
fn is_async(&self) -> bool {
self.tcx.asyncness(self.def_id()).is_async()
}

pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
let did = self.def_id().to_def_id();
if self.tcx.is_closure(did) {
let ty = self.tcx.type_of(did);
let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") };
substs.as_closure().sig()
} else {
self.tcx.fn_sig(did)
}
}
}

pub fn rustc_allow_const_fn_unstable(
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub struct FnCallNonConst<'tcx> {
pub substs: SubstsRef<'tcx>,
pub span: Span,
pub from_hir_call: bool,
pub feature: Option<Symbol>,
}

impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
Expand All @@ -119,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx: &ConstCx<'_, 'tcx>,
_: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
let ConstCx { tcx, param_env, .. } = *ccx;

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

if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
err.help(&format!(
"add `#![feature({})]` to the crate attributes to enable",
feature,
));
}

if let ConstContext::Static(_) = ccx.const_kind() {
err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ impl<'a> ExtCtxt<'a> {
ast::ExprKind::Closure(Box::new(ast::Closure {
binder: ast::ClosureBinder::NotPresent,
capture_clause: ast::CaptureBy::Ref,
constness: ast::Const::No,
asyncness: ast::Async::No,
movability: ast::Movability::Movable,
fn_decl,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,9 @@ declare_features! (
(active, collapse_debuginfo, "1.65.0", Some(100758), None),
/// Allows `async {}` expressions in const contexts.
(active, const_async_blocks, "1.53.0", Some(85368), None),
// Allows limiting the evaluation steps of const expressions
/// Allows `const || {}` closures in const contexts.
(incomplete, const_closures, "CURRENT_RUSTC_VERSION", Some(106003), None),
/// Allows limiting the evaluation steps of const expressions
(active, const_eval_limit, "1.43.0", Some(67217), None),
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
(active, const_extern_fn, "1.40.0", Some(64926), None),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,7 @@ pub struct Crate<'hir> {
pub struct Closure<'hir> {
pub def_id: LocalDefId,
pub binder: ClosureBinder,
pub constness: Constness,
pub capture_clause: CaptureBy,
pub bound_generic_params: &'hir [GenericParam<'hir>],
pub fn_decl: &'hir FnDecl<'hir>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
fn_decl_span: _,
fn_arg_span: _,
movability: _,
constness: _,
}) => {
walk_list!(visitor, visit_generic_param, bound_generic_params);
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,7 @@ impl<'a> State<'a> {
}
hir::ExprKind::Closure(&hir::Closure {
binder,
constness,
capture_clause,
bound_generic_params,
fn_decl,
Expand All @@ -1474,6 +1475,7 @@ impl<'a> State<'a> {
def_id: _,
}) => {
self.print_closure_binder(binder, bound_generic_params);
self.print_constness(constness);
self.print_capture_clause(capture_clause);

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

pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
match header.constness {
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
}
self.print_constness(header.constness);

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

pub fn print_constness(&mut self, s: hir::Constness) {
match s {
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
}
}

pub fn print_unsafety(&mut self, s: hir::Unsafety) {
match s {
hir::Unsafety::Normal => {}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}

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

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,9 @@ impl<'hir> Map<'hir> {
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),

BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
BodyOwnerKind::Fn | BodyOwnerKind::Closure
if self.tcx.is_const_fn_raw(def_id.to_def_id()) =>
{
ConstContext::ConstFn
}
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ pub enum SelectionCandidate<'tcx> {

/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for an `||` expression.
ClosureCandidate,
ClosureCandidate {
is_const: bool,
},

/// Implementation of a `Generator` trait by one of the anonymous types
/// generated for a generator.
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2465,8 +2465,10 @@ impl<'tcx> TyCtxt<'tcx> {

#[inline]
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
&& self.constness(def_id) == hir::Constness::Const
matches!(
self.def_kind(def_id),
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
) && self.constness(def_id) == hir::Constness::Const
}

#[inline]
Expand Down
Loading

0 comments on commit 279f1c9

Please sign in to comment.