diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4a2992038003c..46b33a481214b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -231,6 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.id, expr_hir_id, *coroutine_kind, + *constness, fn_decl, body, *fn_decl_span, @@ -1061,7 +1062,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - constness: Const, + mut constness: Const, movability: Movability, decl: &FnDecl, body: &Expr, @@ -1071,11 +1072,18 @@ impl<'hir> LoweringContext<'_, 'hir> { 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; @@ -1158,6 +1166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_id: NodeId, closure_hir_id: HirId, coroutine_kind: CoroutineKind, + constness: Const, decl: &FnDecl, body: &Expr, fn_decl_span: Span, @@ -1204,6 +1213,10 @@ impl<'hir> LoweringContext<'_, 'hir> { 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, @@ -1217,7 +1230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // 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) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ed78b77a704f6..e2ac38caf2950 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,3 +1,5 @@ +use std::mem; + use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; @@ -345,6 +347,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + header.constness, ); let itctx = ImplTraitContext::Universal; @@ -1024,6 +1027,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(body), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1217,6 +1221,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + sig.header.constness, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1346,11 +1351,13 @@ impl<'hir> LoweringContext<'_, 'hir> { 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 @@ impl<'hir> LoweringContext<'_, 'hir> { &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 @@ impl<'hir> LoweringContext<'_, 'hir> { 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 @@ impl<'hir> LoweringContext<'_, 'hir> { ( &[], 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 @@ impl<'hir> LoweringContext<'_, 'hir> { 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 @@ impl<'hir> LoweringContext<'_, 'hir> { }; 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| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c3525d1246705..e8092b540ec87 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -129,6 +129,7 @@ struct LoweringContext<'a, 'hir> { loop_scope: Option, 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 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 39e886227d946..ae356118c93ec 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -429,7 +429,7 @@ declare_features! ( /// 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. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e16fa5492979f..98999232a7435 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -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:?}"), }; diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index cf1b863f754c8..fc2a7fbd4fa9c 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -310,16 +310,18 @@ impl<'tcx> TyCtxt<'tcx> { /// 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 { - let def_id = def_id.into(); + pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option { + 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, }; diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index e59573976af52..5179a77d6cb6f 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -402,6 +402,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { 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) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6abe7d1466990..01c351de93198 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2118,11 +2118,7 @@ impl<'tcx> TyCtxt<'tcx> { // 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 diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 05ea217c1de08..cd74e87b670f1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -661,10 +661,11 @@ fn coroutine_closure_to_ambiguous_coroutine( /// /// 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( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder, I::FunctionId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder, 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( 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( 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(..) => { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 4da76b88b5de0..4b1e4b2de571d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -272,6 +272,7 @@ where todo!("Fn* are not yet const") } + #[instrument(level = "trace", skip_all, ret)] fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -289,7 +290,7 @@ where 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| { ( diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 66c949a38cea7..026ab3a527a1c 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -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 diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e77e7af071b90..25f7c36e9985d 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -308,6 +308,7 @@ pub trait Interner: 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, diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr similarity index 82% rename from tests/ui/traits/const-traits/call-const-closure.stderr rename to tests/ui/traits/const-traits/call-const-closure.next.stderr index 9a851a97f186a..16b936d58aaf6 100644 --- a/tests/ui/traits/const-traits/call-const-closure.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -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())(); diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr new file mode 100644 index 0000000000000..16b936d58aaf6 --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -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`. diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs index c4293579aea8e..2cf561ae6db14 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -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 @@ impl Bar for () { 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() {} diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index 360c08e1b7fe9..71dea1ef4e049 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -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() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr deleted file mode 100644 index 8e32cab6dfcfb..0000000000000 --- a/tests/ui/traits/const-traits/call.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs index 7a44920bb729d..55fae27eb6dd7 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(const_closures, const_trait_impl)] const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> [u32; N] { @@ -16,9 +15,9 @@ const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> } 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]); } diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr index 1eadd1d842691..448b343e2caa4 100644 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr @@ -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); | - ^ diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs deleted file mode 100644 index af7375172e674..0000000000000 --- a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ check-pass - -#![allow(incomplete_features)] -#![feature(const_closures, const_trait_impl)] - -const fn create_array(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]); -} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs index 35127eda5c039..ce20b05a8133c 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.rs +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs @@ -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 || {} diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr deleted file mode 100644 index 1d8d5ff1b4f2e..0000000000000 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs deleted file mode 100644 index e355ee724d1bd..0000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs +++ /dev/null @@ -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())(); -} diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr deleted file mode 100644 index dab3f14161fac..0000000000000 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/traits/const-traits/gate.rs b/tests/ui/traits/const-traits/gate.rs index 3f348c8413930..c9f56df35531f 100644 --- a/tests/ui/traits/const-traits/gate.rs +++ b/tests/ui/traits/const-traits/gate.rs @@ -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 || {})); diff --git a/tests/ui/traits/const-traits/gate.stderr b/tests/ui/traits/const-traits/gate.stderr index 6bef2c511ce7d..788878292b6ff 100644 --- a/tests/ui/traits/const-traits/gate.stderr +++ b/tests/ui/traits/const-traits/gate.stderr @@ -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 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 { (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 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: `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)] | -LL | (const || {})(); - | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 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 E0658`. diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs index 8ee3db445d072..1f35abbb9d6af 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs @@ -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!(), } diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr index abbe0a0070aa2..73340f15cbb8a 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr @@ -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 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 2 previous errors +error: aborting due to 1 previous error -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`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index de5bedf0ace76..58402cbaec81b 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -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 } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index efbedca1c7e7f..f5521b90cc2d9 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -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`.