mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #153818 - oli-obk:const-closures, r=fee1-dead
Reimplement const closures Tracking issue: rust-lang/rust#106003 Best reviewed commit-by-commit The old solver can't handle `for<'a> |x: &'a()| ()` closures in const contexts, but that feature is unstable itself, so we can just leave it to the next solver to handle. We need a lot more tests, we're testing the bare minimum of success and failure paths right now. r? @fee1-dead
This commit is contained in:
@@ -230,6 +230,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
||||
e.id,
|
||||
expr_hir_id,
|
||||
*coroutine_kind,
|
||||
*constness,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
@@ -1060,7 +1061,7 @@ fn lower_expr_closure(
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
constness: Const,
|
||||
mut constness: Const,
|
||||
movability: Movability,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
@@ -1070,11 +1071,18 @@ fn lower_expr_closure(
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
if !self.is_in_const_context {
|
||||
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
|
||||
constness = Const::No;
|
||||
}
|
||||
}
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
|
||||
// FIXME(contracts): Support contracts on closures?
|
||||
let body_id = this.lower_fn_body(decl, None, |this| {
|
||||
let body_id = this.lower_fn_body(decl, None, constness, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
@@ -1157,6 +1165,7 @@ fn lower_expr_coroutine_closure(
|
||||
closure_id: NodeId,
|
||||
closure_hir_id: HirId,
|
||||
coroutine_kind: CoroutineKind,
|
||||
constness: Const,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
@@ -1203,6 +1212,10 @@ fn lower_expr_coroutine_closure(
|
||||
let fn_decl =
|
||||
self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
self.dcx().span_err(span, "const coroutines are not supported");
|
||||
}
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
@@ -1216,7 +1229,7 @@ fn lower_expr_coroutine_closure(
|
||||
// knows that a `FnDecl` output type like `-> &str` actually means
|
||||
// "coroutine that returns &str", rather than directly returning a `&str`.
|
||||
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
|
||||
constness: hir::Constness::NotConst,
|
||||
constness: self.lower_constness(constness),
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::mem;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
@@ -345,6 +347,7 @@ fn lower_item_kind(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
header.constness,
|
||||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
@@ -1024,6 +1027,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
Some(body),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1217,6 +1221,7 @@ fn lower_impl_item(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1346,11 +1351,13 @@ pub(super) fn lower_body(
|
||||
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
|
||||
) -> hir::BodyId {
|
||||
let prev_coroutine_kind = self.coroutine_kind.take();
|
||||
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
|
||||
let task_context = self.task_context.take();
|
||||
let (parameters, result) = f(self);
|
||||
let body_id = self.record_body(parameters, result);
|
||||
self.task_context = task_context;
|
||||
self.coroutine_kind = prev_coroutine_kind;
|
||||
self.is_in_const_context = prev_is_in_const_context;
|
||||
body_id
|
||||
}
|
||||
|
||||
@@ -1369,9 +1376,13 @@ pub(super) fn lower_fn_body(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
self.lower_body(|this| {
|
||||
if let Const::Yes(_) = constness {
|
||||
this.is_in_const_context = true;
|
||||
}
|
||||
let params =
|
||||
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
|
||||
|
||||
@@ -1389,8 +1400,9 @@ fn lower_fn_body_block(
|
||||
decl: &FnDecl,
|
||||
body: &Block,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
|
||||
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
|
||||
}
|
||||
|
||||
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
|
||||
@@ -1398,7 +1410,10 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi
|
||||
(
|
||||
&[],
|
||||
match expr {
|
||||
Some(expr) => this.lower_expr_mut(expr),
|
||||
Some(expr) => {
|
||||
this.is_in_const_context = true;
|
||||
this.lower_expr_mut(expr)
|
||||
}
|
||||
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
|
||||
},
|
||||
)
|
||||
@@ -1417,12 +1432,13 @@ fn lower_maybe_coroutine_body(
|
||||
body: Option<&Block>,
|
||||
attrs: &'hir [hir::Attribute],
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
let Some(body) = body else {
|
||||
// Functions without a body are an error, except if this is an intrinsic. For those we
|
||||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||
// this as a special case.
|
||||
return self.lower_fn_body(decl, contract, |this| {
|
||||
return self.lower_fn_body(decl, contract, constness, |this| {
|
||||
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
|
||||
let span = this.lower_span(span);
|
||||
let empty_block = hir::Block {
|
||||
@@ -1447,7 +1463,7 @@ fn lower_maybe_coroutine_body(
|
||||
};
|
||||
let Some(coroutine_kind) = coroutine_kind else {
|
||||
// Typical case: not a coroutine.
|
||||
return self.lower_fn_body_block(decl, body, contract);
|
||||
return self.lower_fn_body_block(decl, body, contract, constness);
|
||||
};
|
||||
// FIXME(contracts): Support contracts on async fn.
|
||||
self.lower_body(|this| {
|
||||
|
||||
@@ -129,6 +129,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
loop_scope: Option<HirId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_dyn_type: bool,
|
||||
is_in_const_context: bool,
|
||||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
@@ -190,6 +191,7 @@ fn new(
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_dyn_type: false,
|
||||
is_in_const_context: false,
|
||||
coroutine_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
|
||||
@@ -431,7 +431,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
/// Allows defining and calling c-variadic functions in const contexts.
|
||||
(unstable, const_c_variadic, "1.95.0", Some(151787)),
|
||||
/// Allows `const || {}` closures in const contexts.
|
||||
(incomplete, const_closures, "1.68.0", Some(106003)),
|
||||
(unstable, const_closures, "1.68.0", Some(106003)),
|
||||
/// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.
|
||||
(unstable, const_destruct, "1.85.0", Some(133214)),
|
||||
/// Allows `for _ in _` loops in const contexts.
|
||||
|
||||
@@ -1069,6 +1069,9 @@ pub(super) fn const_conditions<'tcx>(
|
||||
},
|
||||
// N.B. Tuple ctors are unconditionally constant.
|
||||
Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
|
||||
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_), .. }) => {
|
||||
(hir::Generics::empty(), None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
|
||||
}
|
||||
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
|
||||
};
|
||||
|
||||
|
||||
@@ -310,16 +310,18 @@ pub fn hir_body_owner_kind(self, def_id: impl Into<DefId>) -> BodyOwnerKind {
|
||||
/// This should only be used for determining the context of a body, a return
|
||||
/// value of `Some` does not always suggest that the owner of the body is `const`,
|
||||
/// just that it has to be checked as if it were.
|
||||
pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
|
||||
let def_id = def_id.into();
|
||||
pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option<ConstContext> {
|
||||
let def_id = local_def_id.into();
|
||||
let ccx = match self.hir_body_owner_kind(def_id) {
|
||||
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
|
||||
BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
|
||||
|
||||
BodyOwnerKind::Fn if self.is_constructor(def_id) => return None,
|
||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
|
||||
ConstContext::ConstFn
|
||||
// Const closures use their parent's const context
|
||||
BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
|
||||
return self.hir_body_const_context(self.local_parent(local_def_id));
|
||||
}
|
||||
BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn,
|
||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,
|
||||
};
|
||||
|
||||
|
||||
@@ -402,6 +402,11 @@ fn fn_is_const(self, def_id: DefId) -> bool {
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
fn closure_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::Closure);
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
}
|
||||
|
||||
fn alias_has_const_conditions(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
|
||||
self.is_conditionally_const(def_id)
|
||||
|
||||
@@ -2118,11 +2118,7 @@ pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
|
||||
// FIXME(const_trait_impl): ATPITs could be conditionally const?
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => false,
|
||||
},
|
||||
DefKind::Closure => {
|
||||
// Closures and RPITs will eventually have const conditions
|
||||
// for `[const]` bounds.
|
||||
false
|
||||
}
|
||||
DefKind::Closure => self.constness(def_id) == hir::Constness::Const,
|
||||
DefKind::Ctor(_, CtorKind::Const)
|
||||
| DefKind::Mod
|
||||
| DefKind::Struct
|
||||
|
||||
@@ -661,10 +661,11 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
|
||||
///
|
||||
/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable`
|
||||
/// would be wasteful.
|
||||
#[instrument(level = "trace", skip(cx), ret)]
|
||||
pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
||||
cx: I,
|
||||
self_ty: I::Ty,
|
||||
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
|
||||
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
|
||||
match self_ty.kind() {
|
||||
ty::FnDef(def_id, args) => {
|
||||
let sig = cx.fn_sig(def_id);
|
||||
@@ -675,7 +676,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
||||
Ok((
|
||||
sig.instantiate(cx, args)
|
||||
.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
|
||||
def_id,
|
||||
def_id.into(),
|
||||
args,
|
||||
))
|
||||
} else {
|
||||
@@ -686,9 +687,19 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
||||
ty::FnPtr(..) => {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
// `Closure`s are not const for now.
|
||||
ty::Closure(..) => {
|
||||
return Err(NoSolution);
|
||||
ty::Closure(def, args) => {
|
||||
if cx.closure_is_const(def) {
|
||||
let closure_args = args.as_closure();
|
||||
Ok((
|
||||
closure_args
|
||||
.sig()
|
||||
.map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())),
|
||||
def.into(),
|
||||
args,
|
||||
))
|
||||
} else {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
// `CoroutineClosure`s are not const for now.
|
||||
ty::CoroutineClosure(..) => {
|
||||
|
||||
@@ -272,6 +272,7 @@ fn consider_builtin_fn_ptr_trait_candidate(
|
||||
todo!("Fn* are not yet const")
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all, ret)]
|
||||
fn consider_builtin_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
@@ -289,7 +290,7 @@ fn consider_builtin_fn_trait_candidates(
|
||||
let output_is_sized_pred =
|
||||
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
|
||||
let requirements = cx
|
||||
.const_conditions(def_id.into())
|
||||
.const_conditions(def_id)
|
||||
.iter_instantiated(cx, args)
|
||||
.map(|trait_ref| {
|
||||
(
|
||||
|
||||
@@ -519,10 +519,21 @@ fn evaluate_host_effect_for_fn_goal<'tcx>(
|
||||
// We may support function pointers at some point in the future
|
||||
ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution),
|
||||
|
||||
// Closures could implement `[const] Fn`,
|
||||
// Coroutines could implement `[const] Fn`,
|
||||
// but they don't really need to right now.
|
||||
ty::Closure(..) | ty::CoroutineClosure(_, _) => {
|
||||
return Err(EvaluationFailure::NoSolution);
|
||||
ty::CoroutineClosure(_, _) => return Err(EvaluationFailure::NoSolution),
|
||||
|
||||
ty::Closure(def, args) => {
|
||||
// For now we limit ourselves to closures without binders. The next solver can handle them.
|
||||
let sig =
|
||||
args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?;
|
||||
(
|
||||
def,
|
||||
tcx.mk_args_from_iter(
|
||||
[ty::GenericArg::from(*sig.inputs().get(0).unwrap()), sig.output().into()]
|
||||
.into_iter(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Everything else needs explicit impls or cannot have an impl
|
||||
|
||||
@@ -308,6 +308,7 @@ fn impl_super_outlives(
|
||||
|
||||
fn impl_is_const(self, def_id: Self::ImplId) -> bool;
|
||||
fn fn_is_const(self, def_id: Self::FunctionId) -> bool;
|
||||
fn closure_is_const(self, def_id: Self::ClosureId) -> bool;
|
||||
fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool;
|
||||
fn const_conditions(
|
||||
self,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
error[E0277]: the trait bound `(): [const] Bar` is not satisfied
|
||||
error[E0277]: the trait bound `(): const Bar` is not satisfied
|
||||
--> $DIR/call-const-closure.rs:16:18
|
||||
|
|
||||
LL | (const || ().foo())();
|
||||
@@ -0,0 +1,14 @@
|
||||
error[E0277]: the trait bound `(): const Bar` is not satisfied
|
||||
--> $DIR/call-const-closure.rs:16:18
|
||||
|
|
||||
LL | (const || ().foo())();
|
||||
| ^^^
|
||||
|
|
||||
help: make the `impl` of trait `Bar` `const`
|
||||
|
|
||||
LL | impl const Bar for () {
|
||||
| +++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,8 +1,8 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ revisions: next old
|
||||
//@ edition:2021
|
||||
|
||||
#![feature(const_trait_impl, const_closures)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const trait Bar {
|
||||
fn foo(&self);
|
||||
@@ -14,8 +14,7 @@ fn foo(&self) {}
|
||||
|
||||
const FOO: () = {
|
||||
(const || ().foo())();
|
||||
//~^ ERROR the trait bound `(): [const] Bar` is not satisfied
|
||||
// FIXME(const_trait_impl): The constness environment for const closures is wrong.
|
||||
//~^ ERROR the trait bound `(): const Bar` is not satisfied
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// FIXME(const_trait_impl) check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@revisions: next old
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const _: () = {
|
||||
assert!((const || true)());
|
||||
//~^ ERROR }: [const] Fn()` is not satisfied
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` is not satisfied
|
||||
--> $DIR/call.rs:7:13
|
||||
|
|
||||
LL | assert!((const || true)());
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,4 +1,3 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
|
||||
const fn create_array<const N: usize>(mut f: impl FnMut(usize) -> u32 + Copy) -> [u32; N] {
|
||||
@@ -16,9 +15,9 @@
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = create_array(const |i| 2 * i as u32);
|
||||
let x = const { create_array(const |i| 2 * i as u32) };
|
||||
assert_eq!(x, [0, 2, 4, 6, 8]);
|
||||
|
||||
let y = create_array(const |i| 2 * i as u32 + 1);
|
||||
let y = const { create_array(const |i| 2 * i as u32 + 1) };
|
||||
assert_eq!(y, [1, 3, 5, 7, 9]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0277]: the trait bound `impl FnMut(usize) -> u32 + Copy: [const] FnMut(usize)` is not satisfied
|
||||
--> $DIR/const-closure-issue-125866-error.rs:8:22
|
||||
--> $DIR/const-closure-issue-125866-error.rs:7:22
|
||||
|
|
||||
LL | array[i] = f(i);
|
||||
| - ^
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//@ check-pass
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
|
||||
const fn create_array<const N: usize>(mut f: impl [const] FnMut(usize) -> u32 + Copy) -> [u32; N] {
|
||||
let mut array = [0; N];
|
||||
let mut i = 0;
|
||||
loop {
|
||||
array[i] = f(i);
|
||||
i += 1;
|
||||
if i == N {
|
||||
break;
|
||||
}
|
||||
}
|
||||
array
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = create_array(const |i| 2 * i as u32);
|
||||
assert_eq!(x, [0, 2, 4, 6, 8]);
|
||||
|
||||
let y = create_array(const |i| 2 * i as u32 + 1);
|
||||
assert_eq!(y, [1, 3, 5, 7, 9]);
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
//@ known-bug: #110395
|
||||
// FIXME check-pass
|
||||
//@check-pass
|
||||
|
||||
#![feature(const_trait_impl, const_closures)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const fn test() -> impl [const] Fn() {
|
||||
const move || {}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/const-closure-parse-not-item.rs:8:5: 8:18}: [const] Fn()` is not satisfied
|
||||
--> $DIR/const-closure-parse-not-item.rs:7:20
|
||||
|
|
||||
LL | const fn test() -> impl [const] Fn() {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,16 +0,0 @@
|
||||
//@ known-bug: #110395
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
(const || (()).foo())();
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5
|
||||
|
|
||||
LL | (const || (()).foo())();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,13 +1,14 @@
|
||||
// gate-test-const_closures
|
||||
|
||||
fn main() {
|
||||
(const || {})();
|
||||
const { (const || {})() };
|
||||
//~^ ERROR: const closures are experimental
|
||||
//~| ERROR: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied
|
||||
//~| ERROR: cannot call conditionally-const closure in constants
|
||||
//~| ERROR: `Fn` is not yet stable as a const trait
|
||||
}
|
||||
|
||||
macro_rules! e {
|
||||
($e:expr) => {}
|
||||
($e:expr) => {};
|
||||
}
|
||||
|
||||
e!((const || {}));
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
error[E0658]: const closures are experimental
|
||||
--> $DIR/gate.rs:4:6
|
||||
--> $DIR/gate.rs:4:14
|
||||
|
|
||||
LL | (const || {})();
|
||||
| ^^^^^
|
||||
LL | const { (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
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: const closures are experimental
|
||||
--> $DIR/gate.rs:13:5
|
||||
--> $DIR/gate.rs:14:5
|
||||
|
|
||||
LL | e!((const || {}));
|
||||
| ^^^^^
|
||||
@@ -18,13 +18,29 @@ LL | e!((const || {}));
|
||||
= help: add `#![feature(const_closures)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0277]: the trait bound `{closure@$DIR/gate.rs:4:6: 4:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/gate.rs:4:5
|
||||
error[E0658]: cannot call conditionally-const closure in constants
|
||||
--> $DIR/gate.rs:4:13
|
||||
|
|
||||
LL | (const || {})();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | const { (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
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: `Fn` is not yet stable as a const trait
|
||||
--> $DIR/gate.rs:4:13
|
||||
|
|
||||
LL | const { (const || {})() };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
|
|
||||
LL + #![feature(const_trait_impl)]
|
||||
|
|
||||
|
||||
Some errors have detailed explanations: E0277, E0658.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_trait_impl, const_closures, const_cmp)]
|
||||
|
||||
const fn test() -> impl [const] Fn() {
|
||||
//~^ ERROR: }: [const] Fn()` is not satisfied
|
||||
const move || { //~ ERROR const closures are experimental
|
||||
const move || {
|
||||
let sl: &[u8] = b"foo";
|
||||
|
||||
match sl {
|
||||
[first, remainder @ ..] => {
|
||||
assert_eq!(first, &b'f');
|
||||
// FIXME(const_closures) ^ ERROR cannot call non-const function
|
||||
//~^ ERROR cannot call non-const function
|
||||
}
|
||||
[] => panic!(),
|
||||
}
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
error[E0658]: const closures are experimental
|
||||
--> $DIR/ice-112822-expected-type-for-param.rs:5:5
|
||||
error[E0015]: cannot call non-const function `core::panicking::assert_failed::<&u8, &u8>` in constant functions
|
||||
--> $DIR/ice-112822-expected-type-for-param.rs:9:17
|
||||
|
|
||||
LL | const move || {
|
||||
| ^^^^^
|
||||
LL | assert_eq!(first, &b'f');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= 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
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
note: function `assert_failed` is not const
|
||||
--> $SRC_DIR/core/src/panicking.rs:LL:COL
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0277]: the trait bound `{closure@$DIR/ice-112822-expected-type-for-param.rs:5:5: 5:18}: [const] Fn()` is not satisfied
|
||||
--> $DIR/ice-112822-expected-type-for-param.rs:3:20
|
||||
|
|
||||
LL | const fn test() -> impl [const] Fn() {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0658.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
@@ -13,5 +12,5 @@ fn main() {
|
||||
// #150052 deduplicate diagnostics for const trait supertraits
|
||||
// so we only get one error here
|
||||
(const || { (()).foo() })();
|
||||
//~^ ERROR: }: [const] Fn()` is not satisfied
|
||||
//~^ ERROR: cannot use `const` closures outside of const contexts
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied
|
||||
--> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5
|
||||
error: cannot use `const` closures outside of const contexts
|
||||
--> $DIR/non-const-op-const-closure-non-const-outer.rs:14:6
|
||||
|
|
||||
LL | (const || { (()).foo() })();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
Reference in New Issue
Block a user