Auto merge of #106004 - fee1-dead-contrib:const-closures, r=oli-obk

Const closures

cc https://github.com/rust-lang/rust/issues/106003
This commit is contained in:
bors 2023-01-13 05:04:48 +00:00
commit 279f1c9d8c
56 changed files with 249 additions and 48 deletions

View File

@ -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>,

View File

@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Closure(box Closure {
binder,
capture_clause: _,
constness,
asyncness,
movability: _,
fn_decl,
@ -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);

View File

@ -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,

View File

@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Closure(box Closure {
binder,
capture_clause,
constness,
asyncness,
movability,
fn_decl,
@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder,
*capture_clause,
e.id,
*constness,
*movability,
fn_decl,
body,
@ -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)
@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
constness: Const,
movability: Movability,
decl: &FnDecl,
body: &Expr,
@ -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)
@ -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)
}

View File

@ -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,

View File

@ -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)

View File

@ -399,6 +399,7 @@ impl<'a> State<'a> {
ast::ExprKind::Closure(box ast::Closure {
binder,
capture_clause,
constness,
asyncness,
movability,
fn_decl,
@ -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);

View File

@ -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 {

View File

@ -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"]

View File

@ -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);
}
@ -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;
}
@ -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
@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}
@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}
@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
feature: None,
});
return;
}

View File

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

View File

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

View File

@ -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,

View File

@ -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),

View File

@ -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>,

View File

@ -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)

View File

@ -1464,6 +1464,7 @@ impl<'a> State<'a> {
}
hir::ExprKind::Closure(&hir::Closure {
binder,
constness,
capture_clause,
bound_generic_params,
fn_decl,
@ -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);
@ -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 => {}
@ -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 => {}

View File

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

View File

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

View File

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

View File

@ -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]

View File

@ -1325,7 +1325,10 @@ impl<'a> Parser<'a> {
self.parse_array_or_repeat_expr(Delimiter::Bracket)
} else if self.check_path() {
self.parse_path_start_expr()
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
} else if self.check_keyword(kw::Move)
|| self.check_keyword(kw::Static)
|| self.check_const_closure()
{
self.parse_closure_expr()
} else if self.eat_keyword(kw::If) {
self.parse_if_expr()
@ -2065,6 +2068,8 @@ impl<'a> Parser<'a> {
ClosureBinder::NotPresent
};
let constness = self.parse_constness(Case::Sensitive);
let movability =
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
@ -2111,6 +2116,7 @@ impl<'a> Parser<'a> {
ExprKind::Closure(Box::new(ast::Closure {
binder,
capture_clause,
constness,
asyncness,
movability,
fn_decl,

View File

@ -736,6 +736,16 @@ impl<'a> Parser<'a> {
self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
}
fn check_const_closure(&self) -> bool {
self.is_keyword_ahead(0, &[kw::Const])
&& self.look_ahead(1, |t| match &t.kind {
token::Ident(kw::Move | kw::Static | kw::Async, _)
| token::OrOr
| token::BinOp(token::Or) => true,
_ => false,
})
}
fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const])
&& self.look_ahead(dist + 1, |t| match &t.kind {

View File

@ -498,6 +498,7 @@ symbols! {
console,
const_allocate,
const_async_blocks,
const_closures,
const_compare_raw_pointers,
const_constructor,
const_deallocate,

View File

@ -255,18 +255,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// touch bound regions, they just capture the in-scope
// type/region parameters
match *obligation.self_ty().skip_binder().kind() {
ty::Closure(_, closure_substs) => {
ty::Closure(def_id, closure_substs) => {
let is_const = self.tcx().is_const_fn_raw(def_id);
debug!(?kind, ?obligation, "assemble_unboxed_candidates");
match self.infcx.closure_kind(closure_substs) {
Some(closure_kind) => {
debug!(?closure_kind, "assemble_unboxed_candidates");
if closure_kind.extends(kind) {
candidates.vec.push(ClosureCandidate);
candidates.vec.push(ClosureCandidate { is_const });
}
}
None => {
debug!("assemble_unboxed_candidates: closure_kind not yet known");
candidates.vec.push(ClosureCandidate);
candidates.vec.push(ClosureCandidate { is_const });
}
}
}

View File

@ -84,7 +84,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Object(data)
}
ClosureCandidate => {
ClosureCandidate { .. } => {
let vtable_closure = self.confirm_closure_candidate(obligation)?;
ImplSource::Closure(vtable_closure)
}

View File

@ -1365,15 +1365,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// const param
ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
// const projection
ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {}
ProjectionCandidate(_, ty::BoundConstness::ConstIfConst)
// auto trait impl
AutoImplCandidate => {}
| AutoImplCandidate
// generator / future, this will raise error in other places
// or ignore error with const_async_blocks feature
GeneratorCandidate => {}
FutureCandidate => {}
| GeneratorCandidate
| FutureCandidate
// FnDef where the function is const
FnPointerCandidate { is_const: true } => {}
| FnPointerCandidate { is_const: true }
| ConstDestructCandidate(_)
| ClosureCandidate { is_const: true } => {}
FnPointerCandidate { is_const: false } => {
if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
// Trait methods are not seen as const unless the trait is implemented as const.
@ -1382,7 +1385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
continue
}
}
ConstDestructCandidate(_) => {}
_ => {
// reject all other types of candidates
continue;
@ -1844,7 +1847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(
ParamCandidate(ref cand),
ImplCandidate(..)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }
@ -1863,7 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
(
ImplCandidate(_)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }
@ -1894,7 +1897,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(
ObjectCandidate(_) | ProjectionCandidate(..),
ImplCandidate(..)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }
@ -1907,7 +1910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(
ImplCandidate(..)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }
@ -1989,7 +1992,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Everything else is ambiguous
(
ImplCandidate(_)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }
@ -1999,7 +2002,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate,
ImplCandidate(_)
| ClosureCandidate
| ClosureCandidate { .. }
| GeneratorCandidate
| FutureCandidate
| FnPointerCandidate { .. }

View File

@ -1234,17 +1234,23 @@ where
F: ~const Destruct,
K: ~const Destruct,
{
const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
f: &mut F,
(v1, v2): (&T, &T),
) -> Ordering
where
T: ~const Destruct,
K: ~const Destruct,
{
f(v1).cmp(&f(v2))
cfg_if! {
if #[cfg(bootstrap)] {
const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
f: &mut F,
(v1, v2): (&T, &T),
) -> Ordering
where
T: ~const Destruct,
K: ~const Destruct,
{
f(v1).cmp(&f(v2))
}
min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
} else {
min_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
}
}
min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
}
/// Compares and returns the maximum of two values.

View File

@ -191,6 +191,7 @@
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)]
#![cfg_attr(not(bootstrap), feature(const_closures))]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]

View File

@ -26,6 +26,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
pub(crate) fn rewrite_closure(
binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy,
is_async: &ast::Async,
movability: ast::Movability,
@ -38,7 +39,7 @@ pub(crate) fn rewrite_closure(
debug!("rewrite_closure {:?}", body);
let (prefix, extra_offset) = rewrite_closure_fn_decl(
binder, capture, is_async, movability, fn_decl, body, span, context, shape,
binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape,
)?;
// 1 = space between `|...|` and body.
let body_shape = shape.offset_left(extra_offset)?;
@ -230,6 +231,7 @@ fn rewrite_closure_block(
// Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl(
binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy,
asyncness: &ast::Async,
movability: ast::Movability,
@ -250,6 +252,12 @@ fn rewrite_closure_fn_decl(
ast::ClosureBinder::NotPresent => "".to_owned(),
};
let const_ = if matches!(constness, ast::Const::Yes(_)) {
"const "
} else {
""
};
let immovable = if movability == ast::Movability::Static {
"static "
} else {
@ -264,7 +272,7 @@ fn rewrite_closure_fn_decl(
// 4 = "|| {".len(), which is overconservative when the closure consists of
// a single expression.
let nested_shape = shape
.shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())?
.shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())?
.sub_width(4)?;
// 1 = |
@ -302,7 +310,10 @@ fn rewrite_closure_fn_decl(
.tactic(tactic)
.preserve_newline(true);
let list_str = write_list(&item_vec, &fmt)?;
let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str);
let mut prefix = format!(
"{}{}{}{}{}|{}|",
binder, const_, immovable, is_async, mover, list_str
);
if !ret_str.is_empty() {
if prefix.contains('\n') {
@ -329,6 +340,7 @@ pub(crate) fn rewrite_last_closure(
if let ast::ExprKind::Closure(ref closure) = expr.kind {
let ast::Closure {
ref binder,
constness,
capture_clause,
ref asyncness,
movability,
@ -349,6 +361,7 @@ pub(crate) fn rewrite_last_closure(
};
let (prefix, extra_offset) = rewrite_closure_fn_decl(
binder,
constness,
capture_clause,
asyncness,
movability,

View File

@ -205,6 +205,7 @@ pub(crate) fn format_expr(
}
ast::ExprKind::Closure(ref cl) => closures::rewrite_closure(
&cl.binder,
cl.constness,
cl.capture_clause,
&cl.asyncness,
cl.movability,

View File

@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
g(ExprKind::Closure(Box::new(Closure {
binder: ClosureBinder::NotPresent,
capture_clause: CaptureBy::Value,
constness: Const::No,
asyncness: Async::No,
movability: Movability::Movable,
fn_decl: decl.clone(),

View File

@ -22,6 +22,7 @@ LL | field2: SafeEnum::Variant4("str".to_string())
| ^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell
error[E0010]: allocations are not allowed in statics

View File

@ -6,6 +6,7 @@ LL | (||1usize)()
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -22,6 +22,7 @@ LL | for i in 0..x {
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error[E0658]: mutable references are not allowed in constant functions
--> $DIR/const-fn-error.rs:5:14
@ -39,6 +40,7 @@ LL | for i in 0..x {
| ^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to 4 previous errors

View File

@ -7,6 +7,7 @@ LL | for _ in 0..5 {}
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/const-for.rs:5:14
@ -15,6 +16,7 @@ LL | for _ in 0..5 {}
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to 2 previous errors

View File

@ -6,6 +6,7 @@ LL | const { (|| {})() } => {}
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -6,6 +6,7 @@ LL | || -> u8 { 5 }()
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -6,6 +6,7 @@ LL | const fn foo() { (||{})() }
|
= note: closures need an RFC before allowed to be called in constant functions
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: function pointer calls are not allowed in constant functions
--> $DIR/issue-56164.rs:5:5

View File

@ -6,6 +6,7 @@ LL | a: [(); (|| { 0 })()]
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool {
*a == *b
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
}
const fn g(a: &&&&i64, b: &&&&i64) -> bool {
****a == ****b
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
}
const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
if *l == *r {
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
a = at;
b = bt;
} else {

View File

@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool {
a == b
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
}
const fn g(a: &&&&i64, b: &&&&i64) -> bool {
a == b
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
}
const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
if l == r {
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
a = at;
b = bt;
} else {

View File

@ -5,30 +5,33 @@ LL | a == b
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
help: consider dereferencing here
|
LL | *a == *b
| + +
error[E0015]: cannot call non-const operator in constant functions
--> $DIR/issue-90870.rs:14:5
--> $DIR/issue-90870.rs:15:5
|
LL | a == b
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
help: consider dereferencing here
|
LL | ****a == ****b
| ++++ ++++
error[E0015]: cannot call non-const operator in constant functions
--> $DIR/issue-90870.rs:21:12
--> $DIR/issue-90870.rs:23:12
|
LL | if l == r {
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
help: consider dereferencing here
|
LL | if *l == *r {

View File

@ -47,6 +47,7 @@ LL | [(); { for _ in 0usize.. {}; 0}];
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error[E0658]: mutable references are not allowed in constants
--> $DIR/issue-52443.rs:9:21
@ -64,6 +65,7 @@ LL | [(); { for _ in 0usize.. {}; 0}];
| ^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to 6 previous errors; 1 warning emitted

View File

@ -7,6 +7,6 @@ fn main() {
enum Foo { Bar }
fn foo(x: impl Iterator<Item = Foo>) {
for <Foo>::Bar in x {}
//~^ ERROR expected one of `move`, `static`, `|`
//~^ ERROR expected one of `const`, `move`, `static`, `|`
//~^^ ERROR `for<...>` binders for closures are experimental
}

View File

@ -1,8 +1,8 @@
error: expected one of `move`, `static`, `|`, or `||`, found `::`
error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::`
--> $DIR/recover-quantified-closure.rs:9:14
|
LL | for <Foo>::Bar in x {}
| ^^ expected one of `move`, `static`, `|`, or `||`
| ^^ expected one of `const`, `move`, `static`, `|`, or `||`
error[E0658]: `for<...>` binders for closures are experimental
--> $DIR/recover-quantified-closure.rs:2:5

View File

@ -5,6 +5,7 @@ LL | let array: [usize; Dim3::dim()]
| ^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
--> $DIR/issue-39559-2.rs:16:15
@ -13,6 +14,7 @@ LL | = [0; Dim3::dim()];
| ^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to 2 previous errors

View File

@ -0,0 +1,10 @@
// check-pass
#![feature(const_closures, const_trait_impl)]
#![allow(incomplete_features)]
pub const _: () = {
assert!((const || true)());
};
fn main() {}

View File

@ -7,6 +7,7 @@ LL | pub struct S(A);
| ^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error

View File

@ -5,6 +5,7 @@ LL | Const.func();
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -0,0 +1,5 @@
// gate-test-const_closures
fn main() {
(const || {})();
//~^ ERROR: const closures are experimental
}

View File

@ -0,0 +1,12 @@
error[E0658]: const closures are experimental
--> $DIR/gate.rs:3:6
|
LL | (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
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,15 @@
#![feature(const_closures, const_trait_impl)]
#![allow(incomplete_features)]
trait Foo {
fn foo(&self);
}
impl Foo for () {
fn foo(&self) {}
}
fn main() {
(const || { (()).foo() })();
//~^ ERROR: cannot call non-const fn
}

View File

@ -0,0 +1,11 @@
error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions
--> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22
|
LL | (const || { (()).foo() })();
| ^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: aborting due to previous error
For more information about this error, try `rustc --explain E0015`.

View File

@ -5,6 +5,7 @@ LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error

View File

@ -5,6 +5,7 @@ LL | Default::default()
| ^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
error: aborting due to previous error