diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 76b84d9da8334..480a5d2f18eca 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` +#![feature(const_fn_transmute)] #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index c1b4cb5f1a8d5..8d4efd8ae8052 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -51,6 +51,12 @@ impl ConstCx<'mir, 'tcx> { pub fn const_kind(&self) -> hir::ConstContext { self.const_kind.expect("`const_kind` must not be called on a non-const fn") } + + pub fn is_const_stable_const_fn(&self) -> bool { + self.const_kind == Some(hir::ConstContext::ConstFn) + && self.tcx.features().staged_api + && is_const_stable_const_fn(self.tcx, self.def_id.to_def_id()) + } } /// Returns `true` if this `DefId` points to one of the official `panic` lang items. @@ -63,3 +69,37 @@ pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: S attr::allow_internal_unstable(&tcx.sess, attrs) .map_or(false, |mut features| features.any(|name| name == feature_gate)) } + +// Returns `true` if the given `const fn` is "const-stable". +// +// Panics if the given `DefId` does not refer to a `const fn`. +// +// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" +// functions can be called in a const-context by users of the stable compiler. "const-stable" +// functions are subject to more stringent restrictions than "const-unstable" functions: They +// cannot use unstable features and can only call other "const-stable" functions. +pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + use attr::{ConstStability, Stability, StabilityLevel}; + + // Const-stability is only relevant for `const fn`. + assert!(tcx.is_const_fn_raw(def_id)); + + // Functions with `#[rustc_const_unstable]` are const-unstable. + match tcx.lookup_const_stability(def_id) { + Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, + None => {} + } + + // Functions with `#[unstable]` are const-unstable. + // + // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability + // attributes. `#[unstable]` should be irrelevant. + if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = + tcx.lookup_stability(def_id) + { + return false; + } + + true +} diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 032cbc23a3f52..e14dcf92b89d2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -10,33 +10,34 @@ use rustc_span::{Span, Symbol}; use super::ConstCx; -/// Emits an error if `op` is not allowed in the given const context. -pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { +/// Emits an error and returns `true` if `op` is not allowed in the given const context. +pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) -> bool { debug!("illegal_op: op={:?}", op); let gate = match op.status_in_item(ccx) { - Status::Allowed => return, + Status::Allowed => return false, Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { - let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(sym::staged_api) - && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable) + let unstable_in_stable = ccx.is_const_stable_const_fn() && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate); if unstable_in_stable { ccx.tcx.sess - .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str())) + .struct_span_err( + span, + &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), + ) .span_suggestion( ccx.body.span, "if it is not part of the public API, make this function unstably const", concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), Applicability::HasPlaceholders, ) - .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") + .note("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") .emit(); } - return; + return unstable_in_stable; } Status::Unstable(gate) => Some(gate), @@ -45,12 +46,14 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { ccx.tcx.sess.miri_unleashed_feature(span, gate); - return; + return false; } op.emit_error(ccx, span); + true } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { Allowed, Unstable(Symbol), @@ -59,6 +62,8 @@ pub enum Status { /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { + const STOPS_CONST_CHECKING: bool = false; + /// Returns an enum indicating whether this operation is allowed within the given item. fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { Status::Forbidden @@ -93,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug { } } +#[derive(Debug)] +pub struct Abort; +impl NonConstOp for Abort { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "abort is not stable in const fn") + } +} + +#[derive(Debug)] +pub struct NonPrimitiveOp; +impl NonConstOp for NonPrimitiveOp { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "only int, `bool` and `char` operations are stable in const fn") + } +} + /// A function call where the callee is a pointer. #[derive(Debug)] pub struct FnCallIndirect; @@ -125,7 +158,8 @@ impl NonConstOp for FnCallNonConst { /// /// Contains the name of the feature that would allow the use of this function. #[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Symbol); +pub struct FnCallUnstable(pub DefId, pub Option); + impl NonConstOp for FnCallUnstable { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let FnCallUnstable(def_id, feature) = *self; @@ -134,13 +168,51 @@ impl NonConstOp for FnCallUnstable { span, &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), ); - if nightly_options::is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); + + if ccx.is_const_stable_const_fn() { + err.help("Const-stable functions can only call other const-stable functions"); + } else if nightly_options::is_nightly_build() { + if let Some(feature) = feature { + err.help(&format!( + "add `#![feature({})]` to the crate attributes to enable", + feature + )); + } } err.emit(); } } +#[derive(Debug)] +pub struct FnPtrCast; +impl NonConstOp for FnPtrCast { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn"); + } +} + +#[derive(Debug)] +pub struct Generator; +impl NonConstOp for Generator { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // FIXME: This means generator-only MIR is only forbidden in const fn. This is for + // compatibility with the old code. Such MIR should be forbidden everywhere. + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "const fn generators are unstable"); + } +} + #[derive(Debug)] pub struct HeapAllocation; impl NonConstOp for HeapAllocation { @@ -403,6 +475,24 @@ impl NonConstOp for ThreadLocalAccess { } } +#[derive(Debug)] +pub struct Transmute; +impl NonConstOp for Transmute { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_transmute) + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "can only call `transmute` from const items, not `const fn`"); + } +} + #[derive(Debug)] pub struct UnionAccess; impl NonConstOp for UnionAccess { @@ -425,3 +515,131 @@ impl NonConstOp for UnionAccess { .emit(); } } + +/// See [#64992]. +/// +/// [#64992]: https://github.com/rust-lang/rust/issues/64992 +#[derive(Debug)] +pub struct UnsizingCast; +impl NonConstOp for UnsizingCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error( + ccx, + span, + "unsizing casts to types besides slices are not allowed in const fn", + ); + } +} + +pub mod ty { + use super::*; + + #[derive(Debug)] + pub struct MutRef; + impl NonConstOp for MutRef { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "mutable references in const fn are unstable"); + } + } + + #[derive(Debug)] + pub struct FnPtr; + impl NonConstOp for FnPtr { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // FIXME: This attribute a hack to allow the specialization of the `futures` API. See + // #59739. We should have a proper feature gate for this. + if ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_allow_const_fn_ptr) { + Status::Allowed + } else { + mcf_status_in_item(ccx) + } + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "function pointers in const fn are unstable"); + } + } + + #[derive(Debug)] + pub struct ImplTrait; + impl NonConstOp for ImplTrait { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error(ccx, span, "`impl Trait` in const fn is unstable"); + } + } + + #[derive(Debug)] + pub struct TraitBound; + impl NonConstOp for TraitBound { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + mcf_emit_error( + ccx, + span, + "trait bounds other than `Sized` on const fn parameters are unstable", + ); + } + } + + /// A trait bound with the `?const Trait` opt-out + #[derive(Debug)] + pub struct TraitBoundNotConst; + impl NonConstOp for TraitBoundNotConst { + const STOPS_CONST_CHECKING: bool = true; + + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_trait_bound_opt_out) + } + + fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_trait_bound_opt_out, + span, + "`?const Trait` syntax is unstable", + ) + .emit() + } + } +} + +fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn) + } +} + +fn mcf_emit_error(ccx: &ConstCx<'_, '_>, span: Span, msg: &str) { + struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg) + .note( + "see issue #57563 \ + for more information", + ) + .help("add `#![feature(const_fn)]` to the crate attributes to enable") + .emit(); +} diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 0228f2d7de023..0c171bbc464a2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; -use rustc_span::{sym, Span}; +use rustc_span::Span; use super::ops; use super::qualifs::{NeedsDrop, Qualif}; @@ -11,13 +11,13 @@ use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { +pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { // Const-stable functions must always use the stable live drop checker. - if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) { + if ccx.is_const_stable_const_fn() { return false; } - tcx.features().const_precise_live_drops + ccx.tcx.features().const_precise_live_drops } /// Look for live drops in a const context. @@ -30,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx, def_id) { + let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; + if !checking_enabled(&ccx) { return; } - let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; visitor.visit_body(body); diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 0501302b7610a..7ea3c1d5a6f85 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -7,19 +7,21 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt}; -use rustc_span::Span; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{ + self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, +}; +use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, TraitEngine}; -use std::borrow::Cow; use std::ops::Deref; use super::ops::{self, NonConstOp}; use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstCx, Qualif}; -use crate::const_eval::{is_const_fn, is_unstable_const_fn}; +use crate::const_eval::is_unstable_const_fn; use crate::dataflow::impls::MaybeMutBorrowedLocals; use crate::dataflow::{self, Analysis}; @@ -176,6 +178,8 @@ pub struct Validator<'mir, 'tcx> { /// The span of the current statement. span: Span, + + const_checking_stopped: bool, } impl Deref for Validator<'mir, 'tcx> { @@ -188,30 +192,60 @@ impl Deref for Validator<'mir, 'tcx> { impl Validator<'mir, 'tcx> { pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Validator { span: ccx.body.span, ccx, qualifs: Default::default() } + Validator { + span: ccx.body.span, + ccx, + qualifs: Default::default(), + const_checking_stopped: false, + } } pub fn check_body(&mut self) { - let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx; - - let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn) - && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id())) - && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; - - if use_min_const_fn_checks { - // Enforce `min_const_fn` for stable `const fn`s. - use crate::transform::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) { - error_min_const_fn_violation(tcx, span, err); - return; + let ConstCx { tcx, body, def_id, .. } = *self.ccx; + + // HACK: This function has side-effects???? Make sure we call it. + let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()); + + // The local type and predicate checks are not free and only relevant for `const fn`s. + if self.const_kind() == hir::ConstContext::ConstFn { + // Prevent const trait methods from being annotated as `stable`. + // FIXME: Do this as part of stability checking. + if self.is_const_stable_const_fn() { + let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + struct_span_err!( + self.ccx.tcx.sess, + self.span, + E0723, + "trait methods cannot be stable const fn" + ) + .emit(); + } } + + self.check_item_predicates(); + + for local in &body.local_decls { + if local.internal { + continue; + } + + self.span = local.source_info.span; + self.check_local_or_return_ty(local.ty); + } + + // impl trait is gone in MIR, so check the return type of a const fn by its signature + // instead of the type of the return place. + self.span = body.local_decls[RETURN_PLACE].source_info.span; + let return_ty = tcx.fn_sig(def_id).output(); + self.check_local_or_return_ty(return_ty.skip_binder()); } self.visit_body(&body); // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Not)) + let should_check_for_sync = self.const_kind() + == hir::ConstContext::Static(hir::Mutability::Not) && !tcx.is_thread_local_static(def_id.to_def_id()); if should_check_for_sync { @@ -226,13 +260,22 @@ impl Validator<'mir, 'tcx> { /// Emits an error if an expression cannot be evaluated in the current context. pub fn check_op(&mut self, op: impl NonConstOp) { - ops::non_const(self.ccx, op, self.span); + self.check_op_spanned(op, self.span); } /// Emits an error at the given `span` if an expression cannot be evaluated in the current /// context. - pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) { - ops::non_const(self.ccx, op, span); + pub fn check_op_spanned(&mut self, op: O, span: Span) { + // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which + // only emitted one error per function. It should be removed and the test output updated. + if self.const_checking_stopped { + return; + } + + let err_emitted = ops::non_const(self.ccx, op, span); + if err_emitted && O::STOPS_CONST_CHECKING { + self.const_checking_stopped = true; + } } fn check_static(&mut self, def_id: DefId, span: Span) { @@ -242,6 +285,100 @@ impl Validator<'mir, 'tcx> { ); self.check_op_spanned(ops::StaticAccess, span) } + + fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) { + for ty in ty.walk() { + let ty = match ty.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + + match *ty.kind() { + ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef), + ty::Opaque(..) => self.check_op(ops::ty::ImplTrait), + ty::FnPtr(..) => self.check_op(ops::ty::FnPtr), + + ty::Dynamic(preds, _) => { + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { + self.check_op(ops::ty::TraitBound) + } + ty::ExistentialPredicate::Trait(trait_ref) => { + if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() { + self.check_op(ops::ty::TraitBound) + } + } + } + } + } + _ => {} + } + } + } + + fn check_item_predicates(&mut self) { + let ConstCx { tcx, def_id, .. } = *self.ccx; + + let mut current = def_id.to_def_id(); + loop { + let predicates = tcx.predicates_of(current); + for (predicate, _) in predicates.predicates { + match predicate.skip_binders() { + ty::PredicateAtom::RegionOutlives(_) + | ty::PredicateAtom::TypeOutlives(_) + | ty::PredicateAtom::WellFormed(_) + | ty::PredicateAtom::Projection(_) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, + ty::PredicateAtom::ObjectSafe(_) => { + bug!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::ClosureKind(..) => { + bug!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Subtype(_) => { + bug!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Trait(pred, constness) => { + if Some(pred.def_id()) == tcx.lang_items().sized_trait() { + continue; + } + match pred.self_ty().kind() { + ty::Param(p) => { + let generics = tcx.generics_of(current); + let def = generics.type_param(p, tcx); + let span = tcx.def_span(def.def_id); + + if constness == hir::Constness::Const { + self.check_op_spanned(ops::ty::TraitBound, span); + } else if !tcx.features().const_fn + || self.ccx.is_const_stable_const_fn() + { + // HACK: We shouldn't need the conditional above, but trait + // bounds on containing impl blocks are wrongly being marked as + // "not-const". + self.check_op_spanned(ops::ty::TraitBound, span); + } + } + // other kinds of bounds are either tautologies + // or cause errors in other passes + _ => continue, + } + } + } + } + match predicates.parent { + Some(parent) => current = parent, + None => break, + } + } + } } impl Visitor<'tcx> for Validator<'mir, 'tcx> { @@ -309,11 +446,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::Use(_) | Rvalue::Repeat(..) - | Rvalue::UnaryOp(UnOp::Neg, _) - | Rvalue::UnaryOp(UnOp::Not, _) - | Rvalue::NullaryOp(NullOp::SizeOf, _) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | Rvalue::Aggregate(..) => {} @@ -363,6 +495,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } + Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + _, + _, + ) => {} + + Rvalue::Cast( + CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, + ), + _, + _, + ) => self.check_op(ops::FnPtrCast), + + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => { + if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { + let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); + + // Casting/coercing things to slices is fine. + if let ty::Slice(_) | ty::Str = unsized_ty.kind() { + return; + } + } + + self.check_op(ops::UnsizingCast); + } + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); @@ -373,8 +534,23 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { + Rvalue::NullaryOp(NullOp::SizeOf, _) => {} + Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + + Rvalue::UnaryOp(_, ref operand) => { + let ty = operand.ty(self.body, self.tcx); + if !(ty.is_integral() || ty.is_bool()) { + self.check_op(ops::NonPrimitiveOp) + } + } + + Rvalue::BinaryOp(op, ref lhs, ref rhs) + | Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { + let lhs_ty = lhs.ty(self.body, self.tcx); + let rhs_ty = rhs.ty(self.body, self.tcx); + + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + assert_eq!(lhs_ty, rhs_ty); assert!( op == BinOp::Eq || op == BinOp::Ne @@ -387,10 +563,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { self.check_op(ops::RawPtrComparison); } - } - Rvalue::NullaryOp(NullOp::Box, _) => { - self.check_op(ops::HeapAllocation); + if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char()) + || !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char()) + { + self.check_op(ops::NonPrimitiveOp) + } } } } @@ -491,14 +669,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + use rustc_target::spec::abi::Abi::RustIntrinsic; + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); self.super_terminator(terminator, location); match &terminator.kind { TerminatorKind::Call { func, .. } => { - let fn_ty = func.ty(self.body, self.tcx); + let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx; + let caller = caller.to_def_id(); + + let fn_ty = func.ty(body, tcx); - let (def_id, substs) = match *fn_ty.kind() { + let (mut callee, substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { @@ -510,38 +693,80 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; - // At this point, we are calling a function whose `DefId` is known... - if is_const_fn(self.tcx, def_id) { - return; - } - - // See if this is a trait method for a concrete type whose impl of that trait is - // `const`. + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. if self.tcx.features().const_trait_impl { - let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs); - debug!("Resolving ({:?}) -> {:?}", def_id, instance); + let instance = Instance::resolve(tcx, param_env, callee, substs); + debug!("Resolving ({:?}) -> {:?}", callee, instance); if let Ok(Some(func)) = instance { if let InstanceDef::Item(def) = func.def { - if is_const_fn(self.tcx, def.did) { - return; - } + callee = def.did; } } } - if is_lang_panic_fn(self.tcx, def_id) { + // At this point, we are calling a function, `callee`, whose `DefId` is known... + + if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); - } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { - // Exempt unstable const fns inside of macros or functions with - // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::lib_feature_allowed; - if !self.span.allows_unstable(feature) - && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature) - { - self.check_op(ops::FnCallUnstable(def_id, feature)); + return; + } + + // HACK: This is to "unstabilize" the `transmute` intrinsic + // within const fns. `transmute` is allowed in all other const contexts. + // This won't really scale to more intrinsics or functions. Let's allow const + // transmutes in const fn before we add more hacks to this. + if tcx.fn_sig(callee).abi() == RustIntrinsic + && tcx.item_name(callee) == sym::transmute + { + self.check_op(ops::Transmute); + return; + } + + if !tcx.is_const_fn_raw(callee) { + self.check_op(ops::FnCallNonConst(callee)); + return; + } + + // If the `const fn` we are trying to call is not const-stable, ensure that we have + // the proper feature gate enabled. + if let Some(gate) = is_unstable_const_fn(tcx, callee) { + if self.span.allows_unstable(gate) { + return; + } + + // Calling an unstable function *always* requires that the corresponding gate + // be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`. + if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // If this crate is not using stability attributes, or the caller is not claiming to be a + // stable `const fn`, that is all that is required. + if !self.ccx.is_const_stable_const_fn() { + return; + } + + // Otherwise, we are something const-stable calling a const-unstable fn. + + if super::allow_internal_unstable(tcx, caller, gate) { + return; + } + + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that + // have no `rustc_const_stable` attributes to be const-unstable as well. This + // should be fixed later. + let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() + && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); + if callee_is_unstable_unmarked { + if self.ccx.is_const_stable_const_fn() { + self.check_op(ops::FnCallUnstable(callee, None)); } - } else { - self.check_op(ops::FnCallNonConst(def_id)); } } @@ -551,7 +776,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) { + if super::post_drop_elaboration::checking_enabled(self.ccx) { return; } @@ -582,37 +807,25 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - TerminatorKind::InlineAsm { .. } => { - self.check_op(ops::InlineAsm); + TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), + TerminatorKind::Abort => self.check_op(ops::Abort), + + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + self.check_op(ops::Generator) } - // FIXME: Some of these are only caught by `min_const_fn`, but should error here - // instead. - TerminatorKind::Abort - | TerminatorKind::Assert { .. } + TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} + | TerminatorKind::Unreachable => {} } } } -fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) { - struct_span_err!(tcx.sess, span, E0723, "{}", msg) - .note( - "see issue #57563 \ - for more information", - ) - .help("add `#![feature(const_fn)]` to the crate attributes to enable") - .emit(); -} - fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) { let ty = body.return_ty(); tcx.infer_ctxt().enter(|infcx| { diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index e7260f3956c38..f801c1ac75bc3 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -217,6 +217,7 @@ impl Cow<'_, B> { /// assert!(!bull.is_borrowed()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_borrowed(&self) -> bool { match *self { Borrowed(_) => true, @@ -239,6 +240,7 @@ impl Cow<'_, B> { /// assert!(!bull.is_owned()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] pub const fn is_owned(&self) -> bool { !self.is_borrowed() } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5ae4b7cf36adc..b33cb3ad8e839 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -86,9 +86,11 @@ #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_btree_new)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index e33dddc4f9841..e6da599006000 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -150,6 +150,7 @@ impl RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[allow_internal_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 3ee0cfbe74759..cff8ff9ac7ad9 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,6 +1,7 @@ #![feature(allocator_api)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a5ddf7619b6dc..a3fbed2ec1254 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -177,6 +177,7 @@ impl Layout { /// sentinel value. Types that lazily allocate must track initialization by /// some other means. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub const fn dangling(&self) -> NonNull { // SAFETY: align is guaranteed to be non-zero diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index bec3adfa98422..fa5655ca35f41 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -56,6 +56,7 @@ unsafe impl Sync for ResumeTy {} #[lang = "from_generator"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[rustc_const_unstable(feature = "gen_future", issue = "50547")] #[inline] pub const fn from_generator(gen: T) -> impl Future where diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9de0f76cbdd2c..86eda843c5bc3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -75,11 +75,13 @@ #![feature(const_float_bits_conv)] #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] +#![feature(const_mut_refs)] #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] #![feature(const_pin)] #![feature(const_fn_union)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 39daad4da127d..ba3d4c075e11f 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -401,6 +401,7 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -413,6 +414,7 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -457,6 +459,7 @@ impl ProcMacro { } } + #[allow_internal_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -465,6 +468,7 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -472,6 +476,7 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index 2cde1f65adf9c..daa577f74bac3 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { + #[allow_internal_unstable(const_fn)] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c5a871e09a6ea..f81ffd2bb9429 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -20,6 +20,7 @@ )] #![feature(nll)] #![feature(staged_api)] +#![feature(const_fn)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] #![feature(extern_types)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 70533189d8e0b..309657e70424b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -237,6 +237,7 @@ #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_transmute)] +#![feature(const_fn)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(const_ipv4)] @@ -306,6 +307,7 @@ #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] +#![feature(thread_local_internals)] #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 3a2218854a730..676eadd1fac3b 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -117,6 +117,7 @@ pub struct Key { pub const INIT: StaticKey = StaticKey::new(None); impl StaticKey { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new(dtor: Option) -> StaticKey { StaticKey { key: atomic::AtomicUsize::new(0), dtor } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 60a05dc5d545b..784b376fcdc06 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -225,6 +225,7 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey { LocalKey { inner } } @@ -497,6 +498,7 @@ pub mod os { } impl Key { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new() -> Key { Key { os: OsStaticKey::new(Some(destroy_value::)), marker: marker::PhantomData } } diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 7dbf7d1a38691..644748786036d 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -5,9 +5,7 @@ const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { - //~^ ERROR E0015 - //~| ERROR E0015 - //~| ERROR E0658 + //~^ ERROR mutable references //~| ERROR E0080 //~| ERROR E0744 sum += i; diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index 6469a65700dad..e18e0a83573ee 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -7,7 +7,7 @@ extern "C" { const extern fn bar() { unsafe { regular_in_block(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } @@ -16,7 +16,7 @@ extern fn regular() {} const extern fn foo() { unsafe { regular(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index a9e2bcdbdd150..348387ff5f827 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,21 +1,15 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); | ^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index 2854c08665716..e0b9e5f33759e 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -6,7 +6,7 @@ const unsafe extern "C" fn closure() -> fn() { || {} } const unsafe extern fn use_float() { 1.0 + 1.0; } //~^ ERROR only int, `bool` and `char` operations are stable in const fn const extern "C" fn ptr_cast(val: *const u8) { val as usize; } -//~^ ERROR casting pointers to ints is unstable in const fn +//~^ ERROR casting pointers to integers fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 146d119fc8f7f..5ca44b3fa7e65 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -16,15 +16,16 @@ LL | const unsafe extern fn use_float() { 1.0 + 1.0; } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/const-extern-fn-min-const-fn.rs:8:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0658, E0723. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 085ff5c58e60c..0446ece421eff 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -1,6 +1,6 @@ // Test that we can't call random fns in a const fn or do other bad things. -#![feature(const_fn, const_transmute)] +#![feature(const_fn, const_fn_transmute)] use std::mem::transmute; diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs index 2207599815ee8..f31543af590d6 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -2,6 +2,7 @@ fn main() { foo(&mut 5); } -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn *x + 1 + } diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index f993a427b4899..9d5ccb880aa1b 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -6,8 +6,8 @@ struct S { impl S { const fn foo(&mut self, x: u32) { + //~^ ERROR mutable references self.state = x; - //~^ contains unimplemented expression } } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index dd05a4c0bb069..785d9c8c2a5fb 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,10 +1,11 @@ -error[E0019]: constant function contains unimplemented expression type - --> $DIR/const_let_assign3.rs:9:9 +error[E0723]: mutable references in const fn are unstable + --> $DIR/const_let_assign3.rs:8:18 | -LL | self.state = x; - | ^^^^^^^^^^^^^^ +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:16:5 @@ -28,5 +29,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0019, E0764. +Some errors have detailed explanations: E0019, E0723, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 3e42cb8c1b074..589085871fba9 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,5 +1,8 @@ const fn foo(a: i32) -> Vec { - vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + vec![1, 2, 3] + //~^ ERROR allocations are not allowed + //~| ERROR unimplemented expression type + //~| ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index 39b223062e986..0f16890141f6b 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -1,13 +1,29 @@ -error[E0723]: heap allocations are not allowed in const fn +error[E0010]: allocations are not allowed in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ allocation not allowed in constant functions + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0019]: constant function contains unimplemented expression type + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/bad_const_fn_body_ice.rs:2:5 | LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0010, E0015, E0019. +For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 2ebd9dd10c512..5dd70acb6ff1c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -78,25 +78,25 @@ const fn foo11(t: T) -> T { t } const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR only int and `bool` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR int, `bool` and `char` operations static BAR: u32 = 42; -const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn -const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics +const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics const fn foo30(x: *const u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2(x: *mut u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } //~^ ERROR mutable references in const fn are unstable diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 9b55b6c6f3bbc..d4498f061c64b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -94,7 +94,7 @@ LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int and `bool` operations are stable in const fn +error[E0723]: only int, `bool` and `char` operations are stable in const fn --> $DIR/min_const_fn.rs:84:35 | LL | const fn foo19_3(f: f32) -> f32 { -f } @@ -112,59 +112,57 @@ LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:90:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:91:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:101:14 @@ -267,5 +265,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } error: aborting due to 30 previous errors -Some errors have detailed explanations: E0493, E0723. -For more information about an error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0013, E0493, E0658, E0723. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index df10f3496c3c8..b83fdf7c656cd 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index bef4f240eeb8b..a1f1f6f52ab2a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,39 +1,38 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:16:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_fn_libstd_stability.rs:38:32 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:39:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs index 6462d736ad194..0c8af5a199aa0 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -12,5 +12,5 @@ fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } Foo { x: () }.y - //~^ accessing union fields is unstable + //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index 427ecff5c6d1a..322052c28fab1 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0723]: accessing union fields is unstable +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe_bad.rs:14:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51909 for more information + = help: add `#![feature(const_fn_union)]` to the crate attributes to enable error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0723. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 12b41ee2b0d6a..902ed435e31bc 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const unsafe fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR can only call other `const fn` +//~^ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index c5ff340dfc6b7..2741a86440487 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,39 +1,38 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 44a6209498737..d17dcb281153c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 31ad12c955113..891c34a888a70 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,30 +1,26 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` +error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index eb250081d6a72..93b67fd7b1428 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern " warning: skipping const checks | +help: skipping check for `const_fn` feature + --> $DIR/abi-mismatch.rs:9:23 + | +LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) { + | ^^^^^ +help: skipping check for `const_fn` feature + --> $DIR/abi-mismatch.rs:10:5 + | +LL | my_fn(); + | ^^^^^ help: skipping check that does not even have a feature gate --> $DIR/abi-mismatch.rs:10:5 | diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs index 67d9f6baca5b4..af6bc2d85fdd6 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ b/src/test/ui/consts/unsizing-cast-non-null.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; pub const fn dangling_slice() -> NonNull<[T]> { NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts are only allowed for references right now + //~^ ERROR: unsizing casts to types besides slices } fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr index 6575355daadd7..dc08ccd02b646 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ b/src/test/ui/consts/unsizing-cast-non-null.stderr @@ -1,4 +1,4 @@ -error[E0723]: unsizing casts are only allowed for references right now +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/unsizing-cast-non-null.rs:6:5 | LL | NonNull::<[T; 0]>::dangling() diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs index 29d3dc18fa7cc..43951c6854b1a 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs @@ -6,6 +6,7 @@ #![stable(feature = "core", since = "1.6.0")] #![feature(rustc_const_unstable)] #![feature(staged_api)] +#![feature(const_fn)] enum Opt { Some(T), diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index be797cae7ca97..928605356a16e 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/unstable-const-fn-in-libcore.rs:23:26 + --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:53 + --> $DIR/unstable-const-fn-in-libcore.rs:19:53 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^ constant functions cannot evaluate destructors @@ -14,7 +14,7 @@ LL | } | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:47 + --> $DIR/unstable-const-fn-in-libcore.rs:19:47 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^^^^ constant functions cannot evaluate destructors diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs index c327667f4cdc7..6d3fc3ce2f171 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.rs +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -12,6 +12,7 @@ fn main() { extern "C" fn ff4() {} // OK. const async unsafe extern "C" fn ff5() {} // OK. //~^ ERROR functions cannot be both `const` and `async` + //~| ERROR `from_generator` is not yet stable as a const fn trait X { async fn ft1(); //~ ERROR functions in traits cannot be declared `async` @@ -34,6 +35,7 @@ fn main() { const async unsafe extern "C" fn ft5() {} //~^ ERROR functions in traits cannot be declared `async` //~| ERROR functions in traits cannot be declared const + //~| ERROR `from_generator` is not yet stable as a const fn //~| ERROR method `ft5` has an incompatible type for trait //~| ERROR functions cannot be both `const` and `async` } @@ -45,6 +47,7 @@ fn main() { extern "C" fn fi4() {} // OK. const async unsafe extern "C" fn fi5() {} //~^ ERROR functions cannot be both `const` and `async` + //~| ERROR `from_generator` is not yet stable as a const fn } extern { diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 4193b3ee695bc..f1e21884040f0 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -8,7 +8,7 @@ LL | const async unsafe extern "C" fn ff5() {} // OK. | `const` because of this error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:17:9 + --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | async fn ft1(); | -----^^^^^^^^^^ @@ -19,19 +19,19 @@ LL | async fn ft1(); = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:19:9 + --> $DIR/fn-header-semantic-fail.rs:20:9 | LL | const fn ft3(); | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^ functions in traits cannot be const error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | const async unsafe extern "C" fn ft5(); = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:21:9 + --> $DIR/fn-header-semantic-fail.rs:22:9 | LL | const async unsafe extern "C" fn ft5(); | ^^^^^-^^^^^---------------------------- @@ -51,7 +51,7 @@ LL | const async unsafe extern "C" fn ft5(); | `const` because of this error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:29:9 + --> $DIR/fn-header-semantic-fail.rs:30:9 | LL | async fn ft1() {} | -----^^^^^^^^^^^^ @@ -62,19 +62,19 @@ LL | async fn ft1() {} = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:32:9 + --> $DIR/fn-header-semantic-fail.rs:33:9 | LL | const fn ft3() {} | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^ functions in traits cannot be const error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | const async unsafe extern "C" fn ft5() {} = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:34:9 + --> $DIR/fn-header-semantic-fail.rs:35:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^-^^^^^------------------------------ @@ -94,7 +94,7 @@ LL | const async unsafe extern "C" fn ft5() {} | `const` because of this error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:46:9 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^-^^^^^------------------------------ @@ -103,7 +103,7 @@ LL | const async unsafe extern "C" fn fi5() {} | `const` because of this error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:51:18 + --> $DIR/fn-header-semantic-fail.rs:54:18 | LL | extern { | ------ in this `extern` block @@ -113,7 +113,7 @@ LL | async fn fe1(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:52:19 + --> $DIR/fn-header-semantic-fail.rs:55:19 | LL | extern { | ------ in this `extern` block @@ -124,7 +124,7 @@ LL | unsafe fn fe2(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:53:18 + --> $DIR/fn-header-semantic-fail.rs:56:18 | LL | extern { | ------ in this `extern` block @@ -135,7 +135,7 @@ LL | const fn fe3(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:54:23 + --> $DIR/fn-header-semantic-fail.rs:57:23 | LL | extern { | ------ in this `extern` block @@ -146,7 +146,7 @@ LL | extern "C" fn fe4(); | help: remove the qualifiers: `fn` error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:55:42 + --> $DIR/fn-header-semantic-fail.rs:58:42 | LL | extern { | ------ in this `extern` block @@ -157,7 +157,7 @@ LL | const async unsafe extern "C" fn fe5(); | help: remove the qualifiers: `fn` error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:55:9 + --> $DIR/fn-header-semantic-fail.rs:58:9 | LL | const async unsafe extern "C" fn fe5(); | ^^^^^-^^^^^---------------------------- @@ -165,8 +165,16 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:13:44 + | +LL | const async unsafe extern "C" fn ff5() {} // OK. + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + error[E0053]: method `ft1` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:29:24 + --> $DIR/fn-header-semantic-fail.rs:30:24 | LL | async fn ft1(); | - type in trait @@ -181,7 +189,7 @@ LL | async fn ft1() {} found fn pointer `fn() -> impl Future` error[E0053]: method `ft5` has an incompatible type for trait - --> $DIR/fn-header-semantic-fail.rs:34:48 + --> $DIR/fn-header-semantic-fail.rs:35:48 | LL | const async unsafe extern "C" fn ft5(); | - type in trait @@ -195,7 +203,23 @@ LL | const async unsafe extern "C" fn ft5() {} = note: expected fn pointer `unsafe extern "C" fn()` found fn pointer `unsafe extern "C" fn() -> impl Future` -error: aborting due to 20 previous errors +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:35:48 + | +LL | const async unsafe extern "C" fn ft5() {} + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + +error: `from_generator` is not yet stable as a const fn + --> $DIR/fn-header-semantic-fail.rs:48:48 + | +LL | const async unsafe extern "C" fn fi5() {} + | ^^ + | + = help: add `#![feature(gen_future)]` to the crate attributes to enable + +error: aborting due to 23 previous errors Some errors have detailed explanations: E0053, E0379, E0706. For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3278f35bad2b2..fc85e98ef5326 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -10,7 +10,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR can only call other `const fn` + //~^ ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index b50dd03a86138..c6c78c7d1e895 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,12 +1,9 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-check-fns-in-const-impl.rs:12:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 3994bd97c308e..58041454d5901 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:16:1 + --> $DIR/feature-gate.rs:17:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index d600b53e44875..3506237d1f1d5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -4,6 +4,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] #![feature(rustc_attrs)] +#![feature(const_fn)] trait T { const CONST: i32; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index a1e1c3249af36..8ae8b8868dded 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:12:29 + --> $DIR/feature-gate.rs:13:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs index 03a6fb51503b5..454fde34a2cdc 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs @@ -30,7 +30,7 @@ impl const std::ops::Add for Int { #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> Int { Int(1i32) + Int(2i32) - //~^ ERROR can only call other `const fn` within a `const fn` + //~^ ERROR not yet stable as a const fn } // ok diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index ddef7a3aafc93..54d7cfd5d7973 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -6,18 +6,14 @@ LL | | LL | | Int(self.0 - rhs.0) LL | | } | |_____^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `::add` is not stable as `const fn` +error: `::add` is not yet stable as a const fn --> $DIR/stability.rs:32:5 | LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs index 788f49f743cda..65e0d79308ca3 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.rs +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -8,13 +8,13 @@ fn main() { const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR references in const fn are unstable + let y = &mut x.0; //~ ERROR mutable references //~^ ERROR mutation of layout constrained field is unsafe unsafe { NonZero(1) } } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable + let y = unsafe { &mut x.0 }; //~ ERROR mutable references unsafe { NonZero(1) } }