1 //! Concrete error types for all operations which may be invalid in a certain const context.
3 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
5 use rustc_hir::def_id::DefId;
6 use rustc_infer::infer::TyCtxtInferExt;
7 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
9 use rustc_middle::ty::print::with_no_trimmed_paths;
10 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
11 use rustc_middle::ty::{
12 suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
14 use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
15 use rustc_session::parse::feature_err;
16 use rustc_span::symbol::sym;
17 use rustc_span::{BytePos, Pos, Span, Symbol};
18 use rustc_trait_selection::traits::SelectionContext;
21 use crate::util::{call_kind, CallDesugaringKind, CallKind};
23 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
30 #[derive(Clone, Copy)]
31 pub enum DiagnosticImportance {
32 /// An operation that must be removed for const-checking to pass.
35 /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
39 /// An operation that is not *always* allowed in a const context.
40 pub trait NonConstOp<'tcx>: std::fmt::Debug {
41 /// Returns an enum indicating whether this operation is allowed within the given item.
42 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
46 fn importance(&self) -> DiagnosticImportance {
47 DiagnosticImportance::Primary
50 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
54 pub struct FloatingPointOp;
55 impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
56 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
57 if ccx.const_kind() == hir::ConstContext::ConstFn {
58 Status::Unstable(sym::const_fn_floating_point_arithmetic)
64 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
66 &ccx.tcx.sess.parse_sess,
67 sym::const_fn_floating_point_arithmetic,
69 &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
74 /// A function call where the callee is a pointer.
76 pub struct FnCallIndirect;
77 impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
78 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
79 ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
83 /// A function call where the callee is not marked as `const`.
84 #[derive(Debug, Clone, Copy)]
85 pub struct FnCallNonConst<'tcx> {
88 pub substs: SubstsRef<'tcx>,
90 pub from_hir_call: bool,
93 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
94 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
95 let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
96 let ConstCx { tcx, param_env, .. } = *ccx;
98 let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
99 let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
101 match self_ty.kind() {
104 if let Some(generics) = caller
106 .map(|id| tcx.hir().local_def_id_to_hir_id(id))
107 .map(|id| tcx.hir().get(id))
109 .and_then(|node| node.generics())
111 let constraint = with_no_trimmed_paths(|| {
112 format!("~const {}", trait_ref.print_only_trait_path())
114 suggest_constraining_type_param(
118 ¶m_ty.name.as_str(),
125 let obligation = Obligation::new(
126 ObligationCause::dummy(),
128 Binder::dummy(TraitPredicate {
130 constness: BoundConstness::NotConst,
131 polarity: ImplPolarity::Positive,
135 let implsrc = tcx.infer_ctxt().enter(|infcx| {
136 let mut selcx = SelectionContext::new(&infcx);
137 selcx.select(&obligation)
140 if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
142 tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
143 err.span_note(span, "impl defined here, but it is not `const`");
152 let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
156 let mut err = match call_kind {
157 CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
160 struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
164 let err = match kind {
165 CallDesugaringKind::ForLoopIntoIter => {
166 error!("cannot convert `{}` into an iterator in {}s")
168 CallDesugaringKind::QuestionBranch => {
169 error!("`?` cannot determine the branch of `{}` in {}s")
171 CallDesugaringKind::QuestionFromResidual => {
172 error!("`?` cannot convert from residual of `{}` in {}s")
174 CallDesugaringKind::TryBlockFromOutput => {
175 error!("`try` block cannot convert `{}` to the result in {}s")
179 diag_trait(err, self_ty, kind.trait_def_id(tcx))
181 CallKind::FnCall { fn_trait_id, self_ty } => {
182 let mut err = struct_span_err!(
186 "cannot call non-const closure in {}s",
190 match self_ty.kind() {
191 FnDef(def_id, ..) => {
192 let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
193 if ccx.tcx.is_const_fn_raw(*def_id) {
194 span_bug!(span, "calling const FnDef errored when it shouldn't");
197 err.span_note(span, "function defined here, but it is not `const`");
201 "function pointers need an RFC before allowed to be called in {}s",
207 "closures need an RFC before allowed to be called in {}s",
214 diag_trait(err, self_ty, fn_trait_id)
216 CallKind::Operator { trait_id, self_ty, .. } => {
217 let mut err = struct_span_err!(
221 "cannot call non-const operator in {}s",
225 if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
226 match (substs[0].unpack(), substs[1].unpack()) {
227 (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
230 && self_ty.peel_refs().is_primitive() =>
232 let mut num_refs = 0;
233 let mut tmp_ty = self_ty;
234 while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
238 let deref = "*".repeat(num_refs);
240 if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
241 if let Some(eq_idx) = call_str.find("==") {
242 if let Some(rhs_idx) =
243 call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
246 span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
247 let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
248 err.multipart_suggestion(
249 "consider dereferencing here",
251 (span.shrink_to_lo(), deref.clone()),
254 Applicability::MachineApplicable,
264 diag_trait(err, self_ty, trait_id)
266 CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
267 let mut err = struct_span_err!(
271 "cannot perform deref coercion on `{}` in {}s",
276 err.note(&format!("attempting to deref into `{}`", deref_target_ty));
278 // Check first whether the source is accessible (issue #87060)
279 if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
280 err.span_note(deref_target, "deref defined here");
283 diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
285 _ => struct_span_err!(
289 "cannot call non-const fn `{}` in {}s",
290 ccx.tcx.def_path_str_with_substs(callee, substs),
296 "calls in {}s are limited to constant functions, \
297 tuple structs and tuple variants",
305 /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
307 /// Contains the name of the feature that would allow the use of this function.
309 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
311 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
312 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
313 let FnCallUnstable(def_id, feature) = *self;
315 let mut err = ccx.tcx.sess.struct_span_err(
317 &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
320 if ccx.is_const_stable_const_fn() {
321 err.help("const-stable functions can only call other const-stable functions");
322 } else if ccx.tcx.sess.is_nightly_build() {
323 if let Some(feature) = feature {
325 "add `#![feature({})]` to the crate attributes to enable",
336 pub struct FnPtrCast;
337 impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
338 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
339 if ccx.const_kind() != hir::ConstContext::ConstFn {
342 Status::Unstable(sym::const_fn_fn_ptr_basics)
346 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
348 &ccx.tcx.sess.parse_sess,
349 sym::const_fn_fn_ptr_basics,
351 &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
357 pub struct Generator(pub hir::GeneratorKind);
358 impl<'tcx> NonConstOp<'tcx> for Generator {
359 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
360 if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
361 Status::Unstable(sym::const_async_blocks)
367 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
368 let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
369 if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
370 feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
372 ccx.tcx.sess.struct_span_err(span, &msg)
378 pub struct HeapAllocation;
379 impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
380 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
381 let mut err = struct_span_err!(
385 "allocations are not allowed in {}s",
388 err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind()));
389 if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
391 "The value of statics and constants must be known at compile time, \
392 and they live for the entire lifetime of a program. Creating a boxed \
393 value allocates memory on the heap at runtime, and therefore cannot \
394 be done at compile time.",
402 pub struct InlineAsm;
403 impl<'tcx> NonConstOp<'tcx> for InlineAsm {
404 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
409 "inline assembly is not allowed in {}s",
416 pub struct LiveDrop {
417 pub dropped_at: Option<Span>,
419 impl<'tcx> NonConstOp<'tcx> for LiveDrop {
420 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
421 let mut err = struct_span_err!(
425 "destructors cannot be evaluated at compile-time"
427 err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
428 if let Some(span) = self.dropped_at {
429 err.span_label(span, "value is dropped here");
436 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
437 /// the final value of the constant.
438 pub struct TransientCellBorrow;
439 impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
440 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
441 Status::Unstable(sym::const_refs_to_cell)
443 fn importance(&self) -> DiagnosticImportance {
444 // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
445 // not additionally emit a feature gate error if activating the feature gate won't work.
446 DiagnosticImportance::Secondary
448 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
450 &ccx.tcx.sess.parse_sess,
451 sym::const_refs_to_cell,
453 "cannot borrow here, since the borrowed element may contain interior mutability",
459 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
460 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
461 /// it in the future for static items.
462 pub struct CellBorrow;
463 impl<'tcx> NonConstOp<'tcx> for CellBorrow {
464 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
465 let mut err = struct_span_err!(
469 "{}s cannot refer to interior mutable data",
474 "this borrow of an interior mutable value may end up in the final value",
476 if let hir::ConstContext::Static(_) = ccx.const_kind() {
478 "to fix this, the value can be extracted to a separate \
479 `static` item and then referenced",
482 if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
484 "A constant containing interior mutable data behind a reference can allow you
485 to modify that data. This would make multiple uses of a constant to be able to
486 see different values and allow circumventing the `Send` and `Sync` requirements
487 for shared mutable data, which is unsound.",
495 /// This op is for `&mut` borrows in the trailing expression of a constant
496 /// which uses the "enclosing scopes rule" to leak its locals into anonymous
497 /// static or const items.
498 pub struct MutBorrow(pub hir::BorrowKind);
500 impl<'tcx> NonConstOp<'tcx> for MutBorrow {
501 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
505 fn importance(&self) -> DiagnosticImportance {
506 // If there were primary errors (like non-const function calls), do not emit further
507 // errors about mutable references.
508 DiagnosticImportance::Secondary
511 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
512 let raw = match self.0 {
513 hir::BorrowKind::Raw => "raw ",
514 hir::BorrowKind::Ref => "",
517 let mut err = struct_span_err!(
521 "{}mutable references are not allowed in the final value of {}s",
526 if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
528 "References in statics and constants may only refer \
529 to immutable values.\n\n\
530 Statics are shared everywhere, and if they refer to \
531 mutable data one might violate memory safety since \
532 holding multiple mutable references to shared data \
534 If you really want global mutable state, try using \
535 static mut or a global UnsafeCell.",
543 pub struct TransientMutBorrow(pub hir::BorrowKind);
545 impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
546 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
547 Status::Unstable(sym::const_mut_refs)
550 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
551 let raw = match self.0 {
552 hir::BorrowKind::Raw => "raw ",
553 hir::BorrowKind::Ref => "",
557 &ccx.tcx.sess.parse_sess,
560 &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
567 impl<'tcx> NonConstOp<'tcx> for MutDeref {
568 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
569 Status::Unstable(sym::const_mut_refs)
572 fn importance(&self) -> DiagnosticImportance {
573 // Usually a side-effect of a `TransientMutBorrow` somewhere.
574 DiagnosticImportance::Secondary
577 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
579 &ccx.tcx.sess.parse_sess,
582 &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()),
587 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
589 pub struct PanicNonStr;
590 impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
591 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
592 ccx.tcx.sess.struct_span_err(
594 "argument to `panic!()` in a const context must have type `&str`",
599 /// Comparing raw pointers for equality.
600 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
601 /// allocation base addresses that are not known at compile-time.
603 pub struct RawPtrComparison;
604 impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
605 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
609 .struct_span_err(span, "pointers cannot be reliably compared during const eval");
611 "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
612 for more information",
619 pub struct RawMutPtrDeref;
620 impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
621 fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
622 Status::Unstable(sym::const_mut_refs)
625 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
627 &ccx.tcx.sess.parse_sess,
630 &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
635 /// Casting raw pointer or function pointer to an integer.
636 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
637 /// allocation base addresses that are not known at compile-time.
639 pub struct RawPtrToIntCast;
640 impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
641 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
645 .struct_span_err(span, "pointers cannot be cast to integers during const eval");
646 err.note("at compile-time, pointers do not have an integer value");
648 "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
654 /// An access to a (non-thread-local) `static`.
656 pub struct StaticAccess;
657 impl<'tcx> NonConstOp<'tcx> for StaticAccess {
658 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
659 if let hir::ConstContext::Static(_) = ccx.const_kind() {
666 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
667 let mut err = struct_span_err!(
671 "{}s cannot refer to statics",
675 "consider extracting the value of the `static` to a `const`, and referring to that",
677 if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
679 "`static` and `const` variables can refer to other `const` variables. \
680 A `const` variable, however, cannot refer to a `static` variable.",
682 err.help("To fix this, the value can be extracted to a `const` and then used.");
688 /// An access to a thread-local `static`.
690 pub struct ThreadLocalAccess;
691 impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
692 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
697 "thread-local statics cannot be \
698 accessed at compile-time"
703 // Types that cannot appear in the signature or locals of a `const fn`.
708 pub struct MutRef(pub mir::LocalKind);
709 impl<'tcx> NonConstOp<'tcx> for MutRef {
710 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
711 Status::Unstable(sym::const_mut_refs)
714 fn importance(&self) -> DiagnosticImportance {
716 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
717 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
718 DiagnosticImportance::Primary
723 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
725 &ccx.tcx.sess.parse_sess,
728 &format!("mutable references are not allowed in {}s", ccx.const_kind()),
734 pub struct FnPtr(pub mir::LocalKind);
735 impl<'tcx> NonConstOp<'tcx> for FnPtr {
736 fn importance(&self) -> DiagnosticImportance {
738 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
739 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
740 DiagnosticImportance::Primary
745 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
746 if ccx.const_kind() != hir::ConstContext::ConstFn {
749 Status::Unstable(sym::const_fn_fn_ptr_basics)
753 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
755 &ccx.tcx.sess.parse_sess,
756 sym::const_fn_fn_ptr_basics,
758 &format!("function pointers cannot appear in {}s", ccx.const_kind()),
764 pub struct ImplTrait;
765 impl<'tcx> NonConstOp<'tcx> for ImplTrait {
766 fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
767 Status::Unstable(sym::const_impl_trait)
770 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
772 &ccx.tcx.sess.parse_sess,
773 sym::const_impl_trait,
775 &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
781 pub struct TraitBound(pub mir::LocalKind);
782 impl<'tcx> NonConstOp<'tcx> for TraitBound {
783 fn importance(&self) -> DiagnosticImportance {
785 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
786 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
787 DiagnosticImportance::Primary
792 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
793 if ccx.const_kind() != hir::ConstContext::ConstFn {
796 Status::Unstable(sym::const_fn_trait_bound)
800 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
801 let mut err = feature_err(
802 &ccx.tcx.sess.parse_sess,
803 sym::const_fn_trait_bound,
805 "trait bounds other than `Sized` on const fn parameters are unstable",
809 Some(fn_sig) if !fn_sig.span.contains(span) => {
810 err.span_label(fn_sig.span, "function declared as const here");
820 pub struct DynTrait(pub mir::LocalKind);
821 impl<'tcx> NonConstOp<'tcx> for DynTrait {
822 fn importance(&self) -> DiagnosticImportance {
824 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
825 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
826 DiagnosticImportance::Primary
831 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
832 if ccx.const_kind() != hir::ConstContext::ConstFn {
835 Status::Unstable(sym::const_fn_trait_bound)
839 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
840 let mut err = feature_err(
841 &ccx.tcx.sess.parse_sess,
842 sym::const_fn_trait_bound,
844 "trait objects in const fn are unstable",
848 Some(fn_sig) if !fn_sig.span.contains(span) => {
849 err.span_label(fn_sig.span, "function declared as const here");
858 /// A trait bound with the `?const Trait` opt-out
860 pub struct TraitBoundNotConst;
861 impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
862 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
863 Status::Unstable(sym::const_trait_bound_opt_out)
866 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
868 &ccx.tcx.sess.parse_sess,
869 sym::const_trait_bound_opt_out,
871 "`?const Trait` syntax is unstable",