]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`.
[rust.git] / compiler / rustc_const_eval / src / transform / check_consts / ops.rs
1 //! Concrete error types for all operations which may be invalid in a certain const context.
2
3 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
4 use rustc_hir as hir;
5 use rustc_hir::def_id::DefId;
6 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
7 use rustc_middle::{mir, ty::AssocKind};
8 use rustc_session::parse::feature_err;
9 use rustc_span::symbol::sym;
10 use rustc_span::{symbol::Ident, Span, Symbol};
11 use rustc_span::{BytePos, Pos};
12
13 use super::ConstCx;
14
15 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
16 pub enum Status {
17     Allowed,
18     Unstable(Symbol),
19     Forbidden,
20 }
21
22 #[derive(Clone, Copy)]
23 pub enum DiagnosticImportance {
24     /// An operation that must be removed for const-checking to pass.
25     Primary,
26
27     /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
28     Secondary,
29 }
30
31 /// An operation that is not *always* allowed in a const context.
32 pub trait NonConstOp: std::fmt::Debug {
33     /// Returns an enum indicating whether this operation is allowed within the given item.
34     fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
35         Status::Forbidden
36     }
37
38     fn importance(&self) -> DiagnosticImportance {
39         DiagnosticImportance::Primary
40     }
41
42     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
43 }
44
45 #[derive(Debug)]
46 pub struct FloatingPointOp;
47 impl NonConstOp for FloatingPointOp {
48     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
49         if ccx.const_kind() == hir::ConstContext::ConstFn {
50             Status::Unstable(sym::const_fn_floating_point_arithmetic)
51         } else {
52             Status::Allowed
53         }
54     }
55
56     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
57         feature_err(
58             &ccx.tcx.sess.parse_sess,
59             sym::const_fn_floating_point_arithmetic,
60             span,
61             &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
62         )
63     }
64 }
65
66 /// A function call where the callee is a pointer.
67 #[derive(Debug)]
68 pub struct FnCallIndirect;
69 impl NonConstOp for FnCallIndirect {
70     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
71         ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
72     }
73 }
74
75 /// A function call where the callee is not marked as `const`.
76 #[derive(Debug)]
77 pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
78 impl<'a> NonConstOp for FnCallNonConst<'a> {
79     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
80         let mut err = struct_span_err!(
81             ccx.tcx.sess,
82             span,
83             E0015,
84             "calls in {}s are limited to constant functions, \
85              tuple structs and tuple variants",
86             ccx.const_kind(),
87         );
88
89         if let FnCallNonConst(Some((callee, substs))) = *self {
90             if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
91                 if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
92                     ccx.tcx,
93                     Ident::with_dummy_span(sym::eq),
94                     AssocKind::Fn,
95                     trait_def_id,
96                 ) {
97                     if callee == eq_item.def_id && substs.len() == 2 {
98                         match (substs[0].unpack(), substs[1].unpack()) {
99                             (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
100                                 if self_ty == rhs_ty
101                                     && self_ty.is_ref()
102                                     && self_ty.peel_refs().is_primitive() =>
103                             {
104                                 let mut num_refs = 0;
105                                 let mut tmp_ty = self_ty;
106                                 while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
107                                     num_refs += 1;
108                                     tmp_ty = inner_ty;
109                                 }
110                                 let deref = "*".repeat(num_refs);
111
112                                 if let Ok(call_str) =
113                                     ccx.tcx.sess.source_map().span_to_snippet(span)
114                                 {
115                                     if let Some(eq_idx) = call_str.find("==") {
116                                         if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
117                                             .find(|c: char| !c.is_whitespace())
118                                         {
119                                             let rhs_pos = span.lo()
120                                                 + BytePos::from_usize(eq_idx + 2 + rhs_idx);
121                                             let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
122                                             err.multipart_suggestion(
123                                                 "consider dereferencing here",
124                                                 vec![
125                                                     (span.shrink_to_lo(), deref.clone()),
126                                                     (rhs_span, deref),
127                                                 ],
128                                                 Applicability::MachineApplicable,
129                                             );
130                                         }
131                                     }
132                                 }
133                             }
134                             _ => {}
135                         }
136                     }
137                 }
138             }
139         }
140
141         err
142     }
143 }
144
145 /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
146 ///
147 /// Contains the name of the feature that would allow the use of this function.
148 #[derive(Debug)]
149 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
150
151 impl NonConstOp for FnCallUnstable {
152     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
153         let FnCallUnstable(def_id, feature) = *self;
154
155         let mut err = ccx.tcx.sess.struct_span_err(
156             span,
157             &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
158         );
159
160         if ccx.is_const_stable_const_fn() {
161             err.help("const-stable functions can only call other const-stable functions");
162         } else if ccx.tcx.sess.is_nightly_build() {
163             if let Some(feature) = feature {
164                 err.help(&format!(
165                     "add `#![feature({})]` to the crate attributes to enable",
166                     feature
167                 ));
168             }
169         }
170
171         err
172     }
173 }
174
175 #[derive(Debug)]
176 pub struct FnPtrCast;
177 impl NonConstOp for FnPtrCast {
178     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
179         if ccx.const_kind() != hir::ConstContext::ConstFn {
180             Status::Allowed
181         } else {
182             Status::Unstable(sym::const_fn_fn_ptr_basics)
183         }
184     }
185
186     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
187         feature_err(
188             &ccx.tcx.sess.parse_sess,
189             sym::const_fn_fn_ptr_basics,
190             span,
191             &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
192         )
193     }
194 }
195
196 #[derive(Debug)]
197 pub struct Generator(pub hir::GeneratorKind);
198 impl NonConstOp for Generator {
199     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
200         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
201             Status::Unstable(sym::const_async_blocks)
202         } else {
203             Status::Forbidden
204         }
205     }
206
207     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
208         let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
209         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
210             feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
211         } else {
212             ccx.tcx.sess.struct_span_err(span, &msg)
213         }
214     }
215 }
216
217 #[derive(Debug)]
218 pub struct HeapAllocation;
219 impl NonConstOp for HeapAllocation {
220     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
221         let mut err = struct_span_err!(
222             ccx.tcx.sess,
223             span,
224             E0010,
225             "allocations are not allowed in {}s",
226             ccx.const_kind()
227         );
228         err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind()));
229         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
230             err.note(
231                 "The value of statics and constants must be known at compile time, \
232                  and they live for the entire lifetime of a program. Creating a boxed \
233                  value allocates memory on the heap at runtime, and therefore cannot \
234                  be done at compile time.",
235             );
236         }
237         err
238     }
239 }
240
241 #[derive(Debug)]
242 pub struct InlineAsm;
243 impl NonConstOp for InlineAsm {
244     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
245         struct_span_err!(
246             ccx.tcx.sess,
247             span,
248             E0015,
249             "inline assembly is not allowed in {}s",
250             ccx.const_kind()
251         )
252     }
253 }
254
255 #[derive(Debug)]
256 pub struct LiveDrop {
257     pub dropped_at: Option<Span>,
258 }
259 impl NonConstOp for LiveDrop {
260     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
261         let mut err = struct_span_err!(
262             ccx.tcx.sess,
263             span,
264             E0493,
265             "destructors cannot be evaluated at compile-time"
266         );
267         err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
268         if let Some(span) = self.dropped_at {
269             err.span_label(span, "value is dropped here");
270         }
271         err
272     }
273 }
274
275 #[derive(Debug)]
276 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
277 /// the final value of the constant.
278 pub struct TransientCellBorrow;
279 impl NonConstOp for TransientCellBorrow {
280     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
281         Status::Unstable(sym::const_refs_to_cell)
282     }
283     fn importance(&self) -> DiagnosticImportance {
284         // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
285         // not additionally emit a feature gate error if activating the feature gate won't work.
286         DiagnosticImportance::Secondary
287     }
288     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
289         feature_err(
290             &ccx.tcx.sess.parse_sess,
291             sym::const_refs_to_cell,
292             span,
293             "cannot borrow here, since the borrowed element may contain interior mutability",
294         )
295     }
296 }
297
298 #[derive(Debug)]
299 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
300 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
301 /// it in the future for static items.
302 pub struct CellBorrow;
303 impl NonConstOp for CellBorrow {
304     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
305         let mut err = struct_span_err!(
306             ccx.tcx.sess,
307             span,
308             E0492,
309             "{}s cannot refer to interior mutable data",
310             ccx.const_kind(),
311         );
312         err.span_label(
313             span,
314             "this borrow of an interior mutable value may end up in the final value",
315         );
316         if let hir::ConstContext::Static(_) = ccx.const_kind() {
317             err.help(
318                 "to fix this, the value can be extracted to a separate \
319                 `static` item and then referenced",
320             );
321         }
322         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
323             err.note(
324                 "A constant containing interior mutable data behind a reference can allow you
325                  to modify that data. This would make multiple uses of a constant to be able to
326                  see different values and allow circumventing the `Send` and `Sync` requirements
327                  for shared mutable data, which is unsound.",
328             );
329         }
330         err
331     }
332 }
333
334 #[derive(Debug)]
335 /// This op is for `&mut` borrows in the trailing expression of a constant
336 /// which uses the "enclosing scopes rule" to leak its locals into anonymous
337 /// static or const items.
338 pub struct MutBorrow(pub hir::BorrowKind);
339
340 impl NonConstOp for MutBorrow {
341     fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
342         Status::Forbidden
343     }
344
345     fn importance(&self) -> DiagnosticImportance {
346         // If there were primary errors (like non-const function calls), do not emit further
347         // errors about mutable references.
348         DiagnosticImportance::Secondary
349     }
350
351     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
352         let raw = match self.0 {
353             hir::BorrowKind::Raw => "raw ",
354             hir::BorrowKind::Ref => "",
355         };
356
357         let mut err = struct_span_err!(
358             ccx.tcx.sess,
359             span,
360             E0764,
361             "{}mutable references are not allowed in the final value of {}s",
362             raw,
363             ccx.const_kind(),
364         );
365
366         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
367             err.note(
368                 "References in statics and constants may only refer \
369                       to immutable values.\n\n\
370                       Statics are shared everywhere, and if they refer to \
371                       mutable data one might violate memory safety since \
372                       holding multiple mutable references to shared data \
373                       is not allowed.\n\n\
374                       If you really want global mutable state, try using \
375                       static mut or a global UnsafeCell.",
376             );
377         }
378         err
379     }
380 }
381
382 #[derive(Debug)]
383 pub struct TransientMutBorrow(pub hir::BorrowKind);
384
385 impl NonConstOp for TransientMutBorrow {
386     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
387         Status::Unstable(sym::const_mut_refs)
388     }
389
390     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
391         let raw = match self.0 {
392             hir::BorrowKind::Raw => "raw ",
393             hir::BorrowKind::Ref => "",
394         };
395
396         feature_err(
397             &ccx.tcx.sess.parse_sess,
398             sym::const_mut_refs,
399             span,
400             &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
401         )
402     }
403 }
404
405 #[derive(Debug)]
406 pub struct MutDeref;
407 impl NonConstOp for MutDeref {
408     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
409         Status::Unstable(sym::const_mut_refs)
410     }
411
412     fn importance(&self) -> DiagnosticImportance {
413         // Usually a side-effect of a `TransientMutBorrow` somewhere.
414         DiagnosticImportance::Secondary
415     }
416
417     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
418         feature_err(
419             &ccx.tcx.sess.parse_sess,
420             sym::const_mut_refs,
421             span,
422             &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()),
423         )
424     }
425 }
426
427 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
428 #[derive(Debug)]
429 pub struct PanicNonStr;
430 impl NonConstOp for PanicNonStr {
431     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
432         ccx.tcx.sess.struct_span_err(
433             span,
434             "argument to `panic!()` in a const context must have type `&str`",
435         )
436     }
437 }
438
439 /// Comparing raw pointers for equality.
440 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
441 /// allocation base addresses that are not known at compile-time.
442 #[derive(Debug)]
443 pub struct RawPtrComparison;
444 impl NonConstOp for RawPtrComparison {
445     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
446         let mut err = ccx
447             .tcx
448             .sess
449             .struct_span_err(span, "pointers cannot be reliably compared during const eval");
450         err.note(
451             "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
452             for more information",
453         );
454         err
455     }
456 }
457
458 #[derive(Debug)]
459 pub struct RawMutPtrDeref;
460 impl NonConstOp for RawMutPtrDeref {
461     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
462         Status::Unstable(sym::const_mut_refs)
463     }
464
465     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
466         feature_err(
467             &ccx.tcx.sess.parse_sess,
468             sym::const_mut_refs,
469             span,
470             &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
471         )
472     }
473 }
474
475 /// Casting raw pointer or function pointer to an integer.
476 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
477 /// allocation base addresses that are not known at compile-time.
478 #[derive(Debug)]
479 pub struct RawPtrToIntCast;
480 impl NonConstOp for RawPtrToIntCast {
481     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
482         let mut err = ccx
483             .tcx
484             .sess
485             .struct_span_err(span, "pointers cannot be cast to integers during const eval");
486         err.note("at compile-time, pointers do not have an integer value");
487         err.note(
488             "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
489         );
490         err
491     }
492 }
493
494 /// An access to a (non-thread-local) `static`.
495 #[derive(Debug)]
496 pub struct StaticAccess;
497 impl NonConstOp for StaticAccess {
498     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
499         if let hir::ConstContext::Static(_) = ccx.const_kind() {
500             Status::Allowed
501         } else {
502             Status::Forbidden
503         }
504     }
505
506     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
507         let mut err = struct_span_err!(
508             ccx.tcx.sess,
509             span,
510             E0013,
511             "{}s cannot refer to statics",
512             ccx.const_kind()
513         );
514         err.help(
515             "consider extracting the value of the `static` to a `const`, and referring to that",
516         );
517         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
518             err.note(
519                 "`static` and `const` variables can refer to other `const` variables. \
520                     A `const` variable, however, cannot refer to a `static` variable.",
521             );
522             err.help("To fix this, the value can be extracted to a `const` and then used.");
523         }
524         err
525     }
526 }
527
528 /// An access to a thread-local `static`.
529 #[derive(Debug)]
530 pub struct ThreadLocalAccess;
531 impl NonConstOp for ThreadLocalAccess {
532     fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
533         struct_span_err!(
534             ccx.tcx.sess,
535             span,
536             E0625,
537             "thread-local statics cannot be \
538             accessed at compile-time"
539         )
540     }
541 }
542
543 // Types that cannot appear in the signature or locals of a `const fn`.
544 pub mod ty {
545     use super::*;
546
547     #[derive(Debug)]
548     pub struct MutRef(pub mir::LocalKind);
549     impl NonConstOp for MutRef {
550         fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
551             Status::Unstable(sym::const_mut_refs)
552         }
553
554         fn importance(&self) -> DiagnosticImportance {
555             match self.0 {
556                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
557                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
558                     DiagnosticImportance::Primary
559                 }
560             }
561         }
562
563         fn build_error<'tcx>(
564             &self,
565             ccx: &ConstCx<'_, 'tcx>,
566             span: Span,
567         ) -> DiagnosticBuilder<'tcx> {
568             feature_err(
569                 &ccx.tcx.sess.parse_sess,
570                 sym::const_mut_refs,
571                 span,
572                 &format!("mutable references are not allowed in {}s", ccx.const_kind()),
573             )
574         }
575     }
576
577     #[derive(Debug)]
578     pub struct FnPtr(pub mir::LocalKind);
579     impl NonConstOp for FnPtr {
580         fn importance(&self) -> DiagnosticImportance {
581             match self.0 {
582                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
583                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
584                     DiagnosticImportance::Primary
585                 }
586             }
587         }
588
589         fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
590             if ccx.const_kind() != hir::ConstContext::ConstFn {
591                 Status::Allowed
592             } else {
593                 Status::Unstable(sym::const_fn_fn_ptr_basics)
594             }
595         }
596
597         fn build_error<'tcx>(
598             &self,
599             ccx: &ConstCx<'_, 'tcx>,
600             span: Span,
601         ) -> DiagnosticBuilder<'tcx> {
602             feature_err(
603                 &ccx.tcx.sess.parse_sess,
604                 sym::const_fn_fn_ptr_basics,
605                 span,
606                 &format!("function pointers cannot appear in {}s", ccx.const_kind()),
607             )
608         }
609     }
610
611     #[derive(Debug)]
612     pub struct ImplTrait;
613     impl NonConstOp for ImplTrait {
614         fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
615             Status::Unstable(sym::const_impl_trait)
616         }
617
618         fn build_error<'tcx>(
619             &self,
620             ccx: &ConstCx<'_, 'tcx>,
621             span: Span,
622         ) -> DiagnosticBuilder<'tcx> {
623             feature_err(
624                 &ccx.tcx.sess.parse_sess,
625                 sym::const_impl_trait,
626                 span,
627                 &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
628             )
629         }
630     }
631
632     #[derive(Debug)]
633     pub struct TraitBound(pub mir::LocalKind);
634     impl NonConstOp for TraitBound {
635         fn importance(&self) -> DiagnosticImportance {
636             match self.0 {
637                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
638                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
639                     DiagnosticImportance::Primary
640                 }
641             }
642         }
643
644         fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
645             if ccx.const_kind() != hir::ConstContext::ConstFn {
646                 Status::Allowed
647             } else {
648                 Status::Unstable(sym::const_fn_trait_bound)
649             }
650         }
651
652         fn build_error<'tcx>(
653             &self,
654             ccx: &ConstCx<'_, 'tcx>,
655             span: Span,
656         ) -> DiagnosticBuilder<'tcx> {
657             let mut err = feature_err(
658                 &ccx.tcx.sess.parse_sess,
659                 sym::const_fn_trait_bound,
660                 span,
661                 "trait bounds other than `Sized` on const fn parameters are unstable",
662             );
663
664             match ccx.fn_sig() {
665                 Some(fn_sig) if !fn_sig.span.contains(span) => {
666                     err.span_label(fn_sig.span, "function declared as const here");
667                 }
668                 _ => {}
669             }
670
671             err
672         }
673     }
674
675     #[derive(Debug)]
676     pub struct DynTrait(pub mir::LocalKind);
677     impl NonConstOp for DynTrait {
678         fn importance(&self) -> DiagnosticImportance {
679             match self.0 {
680                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
681                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
682                     DiagnosticImportance::Primary
683                 }
684             }
685         }
686
687         fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
688             if ccx.const_kind() != hir::ConstContext::ConstFn {
689                 Status::Allowed
690             } else {
691                 Status::Unstable(sym::const_fn_trait_bound)
692             }
693         }
694
695         fn build_error<'tcx>(
696             &self,
697             ccx: &ConstCx<'_, 'tcx>,
698             span: Span,
699         ) -> DiagnosticBuilder<'tcx> {
700             let mut err = feature_err(
701                 &ccx.tcx.sess.parse_sess,
702                 sym::const_fn_trait_bound,
703                 span,
704                 "trait objects in const fn are unstable",
705             );
706
707             match ccx.fn_sig() {
708                 Some(fn_sig) if !fn_sig.span.contains(span) => {
709                     err.span_label(fn_sig.span, "function declared as const here");
710                 }
711                 _ => {}
712             }
713
714             err
715         }
716     }
717
718     /// A trait bound with the `?const Trait` opt-out
719     #[derive(Debug)]
720     pub struct TraitBoundNotConst;
721     impl NonConstOp for TraitBoundNotConst {
722         fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
723             Status::Unstable(sym::const_trait_bound_opt_out)
724         }
725
726         fn build_error<'tcx>(
727             &self,
728             ccx: &ConstCx<'_, 'tcx>,
729             span: Span,
730         ) -> DiagnosticBuilder<'tcx> {
731             feature_err(
732                 &ccx.tcx.sess.parse_sess,
733                 sym::const_trait_bound_opt_out,
734                 span,
735                 "`?const Trait` syntax is unstable",
736             )
737         }
738     }
739 }