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 struct Closure {
pub binder: ClosureBinder, pub binder: ClosureBinder,
pub capture_clause: CaptureBy, pub capture_clause: CaptureBy,
pub constness: Const,
pub asyncness: Async, pub asyncness: Async,
pub movability: Movability, pub movability: Movability,
pub fn_decl: P<FnDecl>, pub fn_decl: P<FnDecl>,

View File

@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Closure(box Closure { ExprKind::Closure(box Closure {
binder, binder,
capture_clause: _, capture_clause: _,
constness,
asyncness, asyncness,
movability: _, movability: _,
fn_decl, fn_decl,
@ -1370,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
fn_arg_span: _, fn_arg_span: _,
}) => { }) => {
vis.visit_closure_binder(binder); vis.visit_closure_binder(binder);
visit_constness(constness, vis);
vis.visit_asyncness(asyncness); vis.visit_asyncness(asyncness);
vis.visit_fn_decl(fn_decl); vis.visit_fn_decl(fn_decl);
vis.visit_expr(body); 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, binder,
capture_clause: _, capture_clause: _,
asyncness: _, asyncness: _,
constness: _,
movability: _, movability: _,
fn_decl, fn_decl,
body, body,

View File

@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Closure(box Closure { ExprKind::Closure(box Closure {
binder, binder,
capture_clause, capture_clause,
constness,
asyncness, asyncness,
movability, movability,
fn_decl, fn_decl,
@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder, binder,
*capture_clause, *capture_clause,
e.id, e.id,
*constness,
*movability, *movability,
fn_decl, fn_decl,
body, body,
@ -651,6 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(span), fn_decl_span: self.lower_span(span),
fn_arg_span: None, fn_arg_span: None,
movability: Some(hir::Movability::Static), movability: Some(hir::Movability::Static),
constness: hir::Constness::NotConst,
}); });
hir::ExprKind::Closure(c) hir::ExprKind::Closure(c)
@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder, binder: &ClosureBinder,
capture_clause: CaptureBy, capture_clause: CaptureBy,
closure_id: NodeId, closure_id: NodeId,
constness: Const,
movability: Movability, movability: Movability,
decl: &FnDecl, decl: &FnDecl,
body: &Expr, body: &Expr,
@ -927,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)), fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: generator_option, movability: generator_option,
constness: self.lower_constness(constness),
}); });
hir::ExprKind::Closure(c) hir::ExprKind::Closure(c)
@ -1041,6 +1046,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn_decl_span: self.lower_span(fn_decl_span), fn_decl_span: self.lower_span(fn_decl_span),
fn_arg_span: Some(self.lower_span(fn_arg_span)), fn_arg_span: Some(self.lower_span(fn_arg_span)),
movability: None, movability: None,
constness: hir::Constness::NotConst,
}); });
hir::ExprKind::Closure(c) 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 { match c {
Const::Yes(_) => hir::Constness::Const, Const::Yes(_) => hir::Constness::Const,
Const::No => hir::Constness::NotConst, Const::No => hir::Constness::NotConst,

View File

@ -385,6 +385,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ExprKind::TryBlock(_) => { ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); 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) visit::walk_expr(self, e)

View File

@ -399,6 +399,7 @@ impl<'a> State<'a> {
ast::ExprKind::Closure(box ast::Closure { ast::ExprKind::Closure(box ast::Closure {
binder, binder,
capture_clause, capture_clause,
constness,
asyncness, asyncness,
movability, movability,
fn_decl, fn_decl,
@ -407,6 +408,7 @@ impl<'a> State<'a> {
fn_arg_span: _, fn_arg_span: _,
}) => { }) => {
self.print_closure_binder(binder); self.print_closure_binder(binder);
self.print_constness(*constness);
self.print_movability(*movability); self.print_movability(*movability);
self.print_asyncness(*asyncness); self.print_asyncness(*asyncness);
self.print_capture_clause(*capture_clause); 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 } 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 let Some(fn_kind) = node.fn_kind() {
if fn_kind.constness() == hir::Constness::Const { if fn_kind.constness() == hir::Constness::Const {

View File

@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(trusted_step)] #![feature(trusted_step)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(yeet_expr)] #![feature(yeet_expr)]
#![feature(if_let_guard)]
#![feature(is_some_and)] #![feature(is_some_and)]
#![recursion_limit = "256"] #![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 // 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. // instead of the type of the return place.
self.span = body.local_decls[RETURN_PLACE].source_info.span; 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); self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
} }
@ -730,6 +730,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs, substs,
span: *fn_span, span: *fn_span,
from_hir_call: *from_hir_call, from_hir_call: *from_hir_call,
feature: Some(sym::const_trait_impl),
}); });
return; return;
} }
@ -782,6 +783,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
); );
return; 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))) => { Ok(Some(ImplSource::UserDefined(data))) => {
let callee_name = tcx.item_name(callee); let callee_name = tcx.item_name(callee);
if let Some(&did) = tcx if let Some(&did) = tcx
@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs, substs,
span: *fn_span, span: *fn_span,
from_hir_call: *from_hir_call, from_hir_call: *from_hir_call,
feature: None,
}); });
return; return;
} }
@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs, substs,
span: *fn_span, span: *fn_span,
from_hir_call: *from_hir_call, from_hir_call: *from_hir_call,
feature: None,
}); });
return; return;
} }
@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
substs, substs,
span: *fn_span, span: *fn_span,
from_hir_call: *from_hir_call, from_hir_call: *from_hir_call,
feature: None,
}); });
return; return;
} }

View File

@ -8,7 +8,7 @@ use rustc_attr as attr;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
use rustc_span::Symbol; use rustc_span::Symbol;
pub use self::qualifs::Qualif; pub use self::qualifs::Qualif;
@ -64,6 +64,17 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
fn is_async(&self) -> bool { fn is_async(&self) -> bool {
self.tcx.asyncness(self.def_id()).is_async() 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( pub fn rustc_allow_const_fn_unstable(

View File

@ -111,6 +111,7 @@ pub struct FnCallNonConst<'tcx> {
pub substs: SubstsRef<'tcx>, pub substs: SubstsRef<'tcx>,
pub span: Span, pub span: Span,
pub from_hir_call: bool, pub from_hir_call: bool,
pub feature: Option<Symbol>,
} }
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
@ -119,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx: &ConstCx<'_, 'tcx>, ccx: &ConstCx<'_, 'tcx>,
_: Span, _: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> 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 ConstCx { tcx, param_env, .. } = *ccx;
let diag_trait = |err, self_ty: Ty<'_>, trait_id| { let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@ -318,6 +319,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx.const_kind(), 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() { 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"); 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 { ast::ExprKind::Closure(Box::new(ast::Closure {
binder: ast::ClosureBinder::NotPresent, binder: ast::ClosureBinder::NotPresent,
capture_clause: ast::CaptureBy::Ref, capture_clause: ast::CaptureBy::Ref,
constness: ast::Const::No,
asyncness: ast::Async::No, asyncness: ast::Async::No,
movability: ast::Movability::Movable, movability: ast::Movability::Movable,
fn_decl, fn_decl,

View File

@ -339,7 +339,9 @@ declare_features! (
(active, collapse_debuginfo, "1.65.0", Some(100758), None), (active, collapse_debuginfo, "1.65.0", Some(100758), None),
/// Allows `async {}` expressions in const contexts. /// Allows `async {}` expressions in const contexts.
(active, const_async_blocks, "1.53.0", Some(85368), None), (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), (active, const_eval_limit, "1.43.0", Some(67217), None),
/// Allows the definition of `const extern fn` and `const unsafe extern fn`. /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
(active, const_extern_fn, "1.40.0", Some(64926), None), (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 struct Closure<'hir> {
pub def_id: LocalDefId, pub def_id: LocalDefId,
pub binder: ClosureBinder, pub binder: ClosureBinder,
pub constness: Constness,
pub capture_clause: CaptureBy, pub capture_clause: CaptureBy,
pub bound_generic_params: &'hir [GenericParam<'hir>], pub bound_generic_params: &'hir [GenericParam<'hir>],
pub fn_decl: &'hir FnDecl<'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_decl_span: _,
fn_arg_span: _, fn_arg_span: _,
movability: _, movability: _,
constness: _,
}) => { }) => {
walk_list!(visitor, visit_generic_param, bound_generic_params); walk_list!(visitor, visit_generic_param, bound_generic_params);
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) 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 { hir::ExprKind::Closure(&hir::Closure {
binder, binder,
constness,
capture_clause, capture_clause,
bound_generic_params, bound_generic_params,
fn_decl, fn_decl,
@ -1474,6 +1475,7 @@ impl<'a> State<'a> {
def_id: _, def_id: _,
}) => { }) => {
self.print_closure_binder(binder, bound_generic_params); self.print_closure_binder(binder, bound_generic_params);
self.print_constness(constness);
self.print_capture_clause(capture_clause); self.print_capture_clause(capture_clause);
self.print_closure_params(fn_decl, body); 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) { pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
match header.constness { self.print_constness(header.constness);
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
}
match header.asyncness { match header.asyncness {
hir::IsAsync::NotAsync => {} hir::IsAsync::NotAsync => {}
@ -2292,6 +2291,13 @@ impl<'a> State<'a> {
self.word("fn") 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) { pub fn print_unsafety(&mut self, s: hir::Unsafety) {
match s { match s {
hir::Unsafety::Normal => {} hir::Unsafety::Normal => {}

View File

@ -1686,6 +1686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
ty::Closure(_, substs) => { 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()); 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::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_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 ConstContext::ConstFn
} }
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => { 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 /// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for an `||` expression. /// generated for an `||` expression.
ClosureCandidate, ClosureCandidate {
is_const: bool,
},
/// Implementation of a `Generator` trait by one of the anonymous types /// Implementation of a `Generator` trait by one of the anonymous types
/// generated for a generator. /// generated for a generator.

View File

@ -2465,8 +2465,10 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline] #[inline]
pub fn is_const_fn_raw(self, def_id: DefId) -> bool { pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..)) matches!(
&& self.constness(def_id) == hir::Constness::Const self.def_kind(def_id),
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
) && self.constness(def_id) == hir::Constness::Const
} }
#[inline] #[inline]

View File

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

View File

@ -736,6 +736,16 @@ impl<'a> Parser<'a> {
self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) 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 { fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const]) self.is_keyword_ahead(dist, &[kw::Const])
&& self.look_ahead(dist + 1, |t| match &t.kind { && self.look_ahead(dist + 1, |t| match &t.kind {

View File

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

View File

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

View File

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

View File

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

View File

@ -191,6 +191,7 @@
#![feature(cfg_sanitize)] #![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_target_has_atomic_equal_alignment)]
#![cfg_attr(not(bootstrap), feature(const_closures))]
#![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_floating_point_arithmetic)]
#![feature(const_mut_refs)] #![feature(const_mut_refs)]
#![feature(const_precise_live_drops)] #![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( pub(crate) fn rewrite_closure(
binder: &ast::ClosureBinder, binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy, capture: ast::CaptureBy,
is_async: &ast::Async, is_async: &ast::Async,
movability: ast::Movability, movability: ast::Movability,
@ -38,7 +39,7 @@ pub(crate) fn rewrite_closure(
debug!("rewrite_closure {:?}", body); debug!("rewrite_closure {:?}", body);
let (prefix, extra_offset) = rewrite_closure_fn_decl( 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. // 1 = space between `|...|` and body.
let body_shape = shape.offset_left(extra_offset)?; let body_shape = shape.offset_left(extra_offset)?;
@ -230,6 +231,7 @@ fn rewrite_closure_block(
// Return type is (prefix, extra_offset) // Return type is (prefix, extra_offset)
fn rewrite_closure_fn_decl( fn rewrite_closure_fn_decl(
binder: &ast::ClosureBinder, binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy, capture: ast::CaptureBy,
asyncness: &ast::Async, asyncness: &ast::Async,
movability: ast::Movability, movability: ast::Movability,
@ -250,6 +252,12 @@ fn rewrite_closure_fn_decl(
ast::ClosureBinder::NotPresent => "".to_owned(), ast::ClosureBinder::NotPresent => "".to_owned(),
}; };
let const_ = if matches!(constness, ast::Const::Yes(_)) {
"const "
} else {
""
};
let immovable = if movability == ast::Movability::Static { let immovable = if movability == ast::Movability::Static {
"static " "static "
} else { } else {
@ -264,7 +272,7 @@ fn rewrite_closure_fn_decl(
// 4 = "|| {".len(), which is overconservative when the closure consists of // 4 = "|| {".len(), which is overconservative when the closure consists of
// a single expression. // a single expression.
let nested_shape = shape 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)?; .sub_width(4)?;
// 1 = | // 1 = |
@ -302,7 +310,10 @@ fn rewrite_closure_fn_decl(
.tactic(tactic) .tactic(tactic)
.preserve_newline(true); .preserve_newline(true);
let list_str = write_list(&item_vec, &fmt)?; 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 !ret_str.is_empty() {
if prefix.contains('\n') { if prefix.contains('\n') {
@ -329,6 +340,7 @@ pub(crate) fn rewrite_last_closure(
if let ast::ExprKind::Closure(ref closure) = expr.kind { if let ast::ExprKind::Closure(ref closure) = expr.kind {
let ast::Closure { let ast::Closure {
ref binder, ref binder,
constness,
capture_clause, capture_clause,
ref asyncness, ref asyncness,
movability, movability,
@ -349,6 +361,7 @@ pub(crate) fn rewrite_last_closure(
}; };
let (prefix, extra_offset) = rewrite_closure_fn_decl( let (prefix, extra_offset) = rewrite_closure_fn_decl(
binder, binder,
constness,
capture_clause, capture_clause,
asyncness, asyncness,
movability, movability,

View File

@ -205,6 +205,7 @@ pub(crate) fn format_expr(
} }
ast::ExprKind::Closure(ref cl) => closures::rewrite_closure( ast::ExprKind::Closure(ref cl) => closures::rewrite_closure(
&cl.binder, &cl.binder,
cl.constness,
cl.capture_clause, cl.capture_clause,
&cl.asyncness, &cl.asyncness,
cl.movability, 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 { g(ExprKind::Closure(Box::new(Closure {
binder: ClosureBinder::NotPresent, binder: ClosureBinder::NotPresent,
capture_clause: CaptureBy::Value, capture_clause: CaptureBy::Value,
constness: Const::No,
asyncness: Async::No, asyncness: Async::No,
movability: Movability::Movable, movability: Movability::Movable,
fn_decl: decl.clone(), 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 = 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 = 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 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: 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 = 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 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` note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL --> $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 = 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 error[E0658]: mutable references are not allowed in constant functions
--> $DIR/const-fn-error.rs:5:14 --> $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 = 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 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` note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants = 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 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/const-for.rs:5:14 --> $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 = 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 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: 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 = 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 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: 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 = 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 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: 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 = 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 error: function pointer calls are not allowed in constant functions
--> $DIR/issue-56164.rs:5:5 --> $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: 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 = 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 error: aborting due to previous error

View File

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

View File

@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool {
a == b a == b
//~^ ERROR: cannot call non-const operator in constant functions [E0015] //~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here //~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
} }
const fn g(a: &&&&i64, b: &&&&i64) -> bool { const fn g(a: &&&&i64, b: &&&&i64) -> bool {
a == b a == b
//~^ ERROR: cannot call non-const operator in constant functions [E0015] //~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here //~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
} }
const fn h(mut a: &[u8], mut b: &[u8]) -> bool { 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 { if l == r {
//~^ ERROR: cannot call non-const operator in constant functions [E0015] //~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here //~| HELP: consider dereferencing here
//~| HELP: add `#![feature(const_trait_impl)]`
a = at; a = at;
b = bt; b = bt;
} else { } 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 = 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 help: consider dereferencing here
| |
LL | *a == *b LL | *a == *b
| + + | + +
error[E0015]: cannot call non-const operator in constant functions 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 LL | a == b
| ^^^^^^ | ^^^^^^
| |
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = 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 help: consider dereferencing here
| |
LL | ****a == ****b LL | ****a == ****b
| ++++ ++++ | ++++ ++++
error[E0015]: cannot call non-const operator in constant functions 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 { LL | if l == r {
| ^^^^^^ | ^^^^^^
| |
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = 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 help: consider dereferencing here
| |
LL | if *l == *r { LL | if *l == *r {

View File

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

View File

@ -7,6 +7,6 @@ fn main() {
enum Foo { Bar } enum Foo { Bar }
fn foo(x: impl Iterator<Item = Foo>) { fn foo(x: impl Iterator<Item = Foo>) {
for <Foo>::Bar in x {} 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 //~^^ 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 --> $DIR/recover-quantified-closure.rs:9:14
| |
LL | for <Foo>::Bar in x {} 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 error[E0658]: `for<...>` binders for closures are experimental
--> $DIR/recover-quantified-closure.rs:2:5 --> $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 = 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 error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
--> $DIR/issue-39559-2.rs:16:15 --> $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 = 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 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 = 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) = 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 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 = 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 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 = 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 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 = 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 error: aborting due to previous error