]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Rollup merge of #107773 - Mark-Simulacrum:rename-auto-template, r=estebank
[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 hir::def_id::LocalDefId;
4 use hir::{ConstContext, LangItem};
5 use rustc_errors::{
6     error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
7 };
8 use rustc_hir as hir;
9 use rustc_hir::def_id::DefId;
10 use rustc_infer::infer::TyCtxtInferExt;
11 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
12 use rustc_middle::mir;
13 use rustc_middle::ty::print::with_no_trimmed_paths;
14 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
15 use rustc_middle::ty::{
16     suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty,
17 };
18 use rustc_middle::ty::{Binder, TraitRef};
19 use rustc_session::parse::feature_err;
20 use rustc_span::symbol::sym;
21 use rustc_span::{BytePos, Pos, Span, Symbol};
22 use rustc_trait_selection::traits::SelectionContext;
23
24 use super::ConstCx;
25 use crate::errors;
26 use crate::util::{call_kind, CallDesugaringKind, CallKind};
27
28 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
29 pub enum Status {
30     Allowed,
31     Unstable(Symbol),
32     Forbidden,
33 }
34
35 #[derive(Clone, Copy)]
36 pub enum DiagnosticImportance {
37     /// An operation that must be removed for const-checking to pass.
38     Primary,
39
40     /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
41     Secondary,
42 }
43
44 /// An operation that is not *always* allowed in a const context.
45 pub trait NonConstOp<'tcx>: std::fmt::Debug {
46     /// Returns an enum indicating whether this operation is allowed within the given item.
47     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
48         Status::Forbidden
49     }
50
51     fn importance(&self) -> DiagnosticImportance {
52         DiagnosticImportance::Primary
53     }
54
55     fn build_error(
56         &self,
57         ccx: &ConstCx<'_, 'tcx>,
58         span: Span,
59     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
60 }
61
62 #[derive(Debug)]
63 pub struct FloatingPointOp;
64 impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
65     fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
66         if ccx.const_kind() == hir::ConstContext::ConstFn {
67             Status::Unstable(sym::const_fn_floating_point_arithmetic)
68         } else {
69             Status::Allowed
70         }
71     }
72
73     fn build_error(
74         &self,
75         ccx: &ConstCx<'_, 'tcx>,
76         span: Span,
77     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
78         feature_err(
79             &ccx.tcx.sess.parse_sess,
80             sym::const_fn_floating_point_arithmetic,
81             span,
82             &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
83         )
84     }
85 }
86
87 /// A function call where the callee is a pointer.
88 #[derive(Debug)]
89 pub struct FnCallIndirect;
90 impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
91     fn build_error(
92         &self,
93         ccx: &ConstCx<'_, 'tcx>,
94         span: Span,
95     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
96         ccx.tcx.sess.create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
97     }
98 }
99
100 /// A function call where the callee is not marked as `const`.
101 #[derive(Debug, Clone, Copy)]
102 pub struct FnCallNonConst<'tcx> {
103     pub caller: LocalDefId,
104     pub callee: DefId,
105     pub substs: SubstsRef<'tcx>,
106     pub span: Span,
107     pub from_hir_call: bool,
108     pub feature: Option<Symbol>,
109 }
110
111 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
112     fn build_error(
113         &self,
114         ccx: &ConstCx<'_, 'tcx>,
115         _: Span,
116     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
117         let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
118         let ConstCx { tcx, param_env, .. } = *ccx;
119
120         let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
121             let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
122
123             match self_ty.kind() {
124                 Param(param_ty) => {
125                     debug!(?param_ty);
126                     let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller);
127                     if let Some(generics) = tcx.hir().get(caller_hir_id).generics() {
128                         let constraint = with_no_trimmed_paths!(format!(
129                             "~const {}",
130                             trait_ref.print_only_trait_path()
131                         ));
132                         suggest_constraining_type_param(
133                             tcx,
134                             generics,
135                             err,
136                             &param_ty.name.as_str(),
137                             &constraint,
138                             None,
139                             None,
140                         );
141                     }
142                 }
143                 Adt(..) => {
144                     let obligation = Obligation::new(
145                         tcx,
146                         ObligationCause::dummy(),
147                         param_env,
148                         Binder::dummy(trait_ref),
149                     );
150
151                     let infcx = tcx.infer_ctxt().build();
152                     let mut selcx = SelectionContext::new(&infcx);
153                     let implsrc = selcx.select(&obligation);
154
155                     if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
156                         let span = tcx.def_span(data.impl_def_id);
157                         err.span_note(span, "impl defined here, but it is not `const`");
158                     }
159                 }
160                 _ => {}
161             }
162         };
163
164         let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
165
166         debug!(?call_kind);
167
168         let mut err = match call_kind {
169             CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
170                 macro_rules! error {
171                     ($fmt:literal) => {
172                         struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
173                     };
174                 }
175
176                 let mut err = match kind {
177                     CallDesugaringKind::ForLoopIntoIter => {
178                         error!("cannot convert `{}` into an iterator in {}s")
179                     }
180                     CallDesugaringKind::QuestionBranch => {
181                         error!("`?` cannot determine the branch of `{}` in {}s")
182                     }
183                     CallDesugaringKind::QuestionFromResidual => {
184                         error!("`?` cannot convert from residual of `{}` in {}s")
185                     }
186                     CallDesugaringKind::TryBlockFromOutput => {
187                         error!("`try` block cannot convert `{}` to the result in {}s")
188                     }
189                 };
190
191                 diag_trait(&mut err, self_ty, kind.trait_def_id(tcx));
192                 err
193             }
194             CallKind::FnCall { fn_trait_id, self_ty } => {
195                 let mut err = struct_span_err!(
196                     tcx.sess,
197                     span,
198                     E0015,
199                     "cannot call non-const closure in {}s",
200                     ccx.const_kind(),
201                 );
202
203                 match self_ty.kind() {
204                     FnDef(def_id, ..) => {
205                         let span = tcx.def_span(*def_id);
206                         if ccx.tcx.is_const_fn_raw(*def_id) {
207                             span_bug!(span, "calling const FnDef errored when it shouldn't");
208                         }
209
210                         err.span_note(span, "function defined here, but it is not `const`");
211                     }
212                     FnPtr(..) => {
213                         err.note(&format!(
214                             "function pointers need an RFC before allowed to be called in {}s",
215                             ccx.const_kind()
216                         ));
217                     }
218                     Closure(..) => {
219                         err.note(&format!(
220                             "closures need an RFC before allowed to be called in {}s",
221                             ccx.const_kind()
222                         ));
223                     }
224                     _ => {}
225                 }
226
227                 diag_trait(&mut err, self_ty, fn_trait_id);
228                 err
229             }
230             CallKind::Operator { trait_id, self_ty, .. } => {
231                 let mut err = struct_span_err!(
232                     tcx.sess,
233                     span,
234                     E0015,
235                     "cannot call non-const operator in {}s",
236                     ccx.const_kind()
237                 );
238
239                 if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
240                     match (substs[0].unpack(), substs[1].unpack()) {
241                         (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
242                             if self_ty == rhs_ty
243                                 && self_ty.is_ref()
244                                 && self_ty.peel_refs().is_primitive() =>
245                         {
246                             let mut num_refs = 0;
247                             let mut tmp_ty = self_ty;
248                             while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
249                                 num_refs += 1;
250                                 tmp_ty = *inner_ty;
251                             }
252                             let deref = "*".repeat(num_refs);
253
254                             if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
255                                 if let Some(eq_idx) = call_str.find("==") {
256                                     if let Some(rhs_idx) =
257                                         call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
258                                     {
259                                         let rhs_pos =
260                                             span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
261                                         let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
262                                         err.multipart_suggestion(
263                                             "consider dereferencing here",
264                                             vec![
265                                                 (span.shrink_to_lo(), deref.clone()),
266                                                 (rhs_span, deref),
267                                             ],
268                                             Applicability::MachineApplicable,
269                                         );
270                                     }
271                                 }
272                             }
273                         }
274                         _ => {}
275                     }
276                 }
277
278                 diag_trait(&mut err, self_ty, trait_id);
279                 err
280             }
281             CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
282                 let mut err = struct_span_err!(
283                     tcx.sess,
284                     span,
285                     E0015,
286                     "cannot perform deref coercion on `{}` in {}s",
287                     self_ty,
288                     ccx.const_kind()
289                 );
290
291                 err.note(&format!("attempting to deref into `{}`", deref_target_ty));
292
293                 // Check first whether the source is accessible (issue #87060)
294                 if tcx.sess.source_map().is_span_accessible(deref_target) {
295                     err.span_note(deref_target, "deref defined here");
296                 }
297
298                 diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
299                 err
300             }
301             _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => ccx
302                 .tcx
303                 .sess
304                 .create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }),
305             _ => ccx.tcx.sess.create_err(errors::NonConstFnCall {
306                 span,
307                 def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs),
308                 kind: ccx.const_kind(),
309             }),
310         };
311
312         err.note(&format!(
313             "calls in {}s are limited to constant functions, \
314              tuple structs and tuple variants",
315             ccx.const_kind(),
316         ));
317
318         if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
319             err.help(&format!(
320                 "add `#![feature({})]` to the crate attributes to enable",
321                 feature,
322             ));
323         }
324
325         if let ConstContext::Static(_) = ccx.const_kind() {
326             err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell");
327         }
328
329         err
330     }
331 }
332
333 /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
334 ///
335 /// Contains the name of the feature that would allow the use of this function.
336 #[derive(Debug)]
337 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
338
339 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
340     fn build_error(
341         &self,
342         ccx: &ConstCx<'_, 'tcx>,
343         span: Span,
344     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
345         let FnCallUnstable(def_id, feature) = *self;
346
347         let mut err = ccx
348             .tcx
349             .sess
350             .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
351
352         if ccx.is_const_stable_const_fn() {
353             err.help("const-stable functions can only call other const-stable functions");
354         } else if ccx.tcx.sess.is_nightly_build() {
355             if let Some(feature) = feature {
356                 err.help(&format!(
357                     "add `#![feature({})]` to the crate attributes to enable",
358                     feature
359                 ));
360             }
361         }
362
363         err
364     }
365 }
366
367 #[derive(Debug)]
368 pub struct Generator(pub hir::GeneratorKind);
369 impl<'tcx> NonConstOp<'tcx> for Generator {
370     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
371         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
372             Status::Unstable(sym::const_async_blocks)
373         } else {
374             Status::Forbidden
375         }
376     }
377
378     fn build_error(
379         &self,
380         ccx: &ConstCx<'_, 'tcx>,
381         span: Span,
382     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
383         let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
384         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
385             ccx.tcx.sess.create_feature_err(
386                 errors::UnallowedOpInConstContext { span, msg },
387                 sym::const_async_blocks,
388             )
389         } else {
390             ccx.tcx.sess.create_err(errors::UnallowedOpInConstContext { span, msg })
391         }
392     }
393 }
394
395 #[derive(Debug)]
396 pub struct HeapAllocation;
397 impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
398     fn build_error(
399         &self,
400         ccx: &ConstCx<'_, 'tcx>,
401         span: Span,
402     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
403         ccx.tcx.sess.create_err(errors::UnallowedHeapAllocations {
404             span,
405             kind: ccx.const_kind(),
406             teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()),
407         })
408     }
409 }
410
411 #[derive(Debug)]
412 pub struct InlineAsm;
413 impl<'tcx> NonConstOp<'tcx> for InlineAsm {
414     fn build_error(
415         &self,
416         ccx: &ConstCx<'_, 'tcx>,
417         span: Span,
418     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
419         ccx.tcx.sess.create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
420     }
421 }
422
423 #[derive(Debug)]
424 pub struct LiveDrop<'tcx> {
425     pub dropped_at: Option<Span>,
426     pub dropped_ty: Ty<'tcx>,
427 }
428 impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
429     fn build_error(
430         &self,
431         ccx: &ConstCx<'_, 'tcx>,
432         span: Span,
433     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
434         let mut err = struct_span_err!(
435             ccx.tcx.sess,
436             span,
437             E0493,
438             "destructor of `{}` cannot be evaluated at compile-time",
439             self.dropped_ty,
440         );
441         err.span_label(
442             span,
443             format!("the destructor for this type cannot be evaluated in {}s", ccx.const_kind()),
444         );
445         if let Some(span) = self.dropped_at {
446             err.span_label(span, "value is dropped here");
447         }
448         err
449     }
450 }
451
452 #[derive(Debug)]
453 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
454 /// the final value of the constant.
455 pub struct TransientCellBorrow;
456 impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
457     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
458         Status::Unstable(sym::const_refs_to_cell)
459     }
460     fn importance(&self) -> DiagnosticImportance {
461         // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
462         // not additionally emit a feature gate error if activating the feature gate won't work.
463         DiagnosticImportance::Secondary
464     }
465     fn build_error(
466         &self,
467         ccx: &ConstCx<'_, 'tcx>,
468         span: Span,
469     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
470         ccx.tcx
471             .sess
472             .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
473     }
474 }
475
476 #[derive(Debug)]
477 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
478 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
479 /// it in the future for static items.
480 pub struct CellBorrow;
481 impl<'tcx> NonConstOp<'tcx> for CellBorrow {
482     fn build_error(
483         &self,
484         ccx: &ConstCx<'_, 'tcx>,
485         span: Span,
486     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
487         // FIXME: Maybe a more elegant solution to this if else case
488         if let hir::ConstContext::Static(_) = ccx.const_kind() {
489             ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
490                 span,
491                 opt_help: Some(()),
492                 kind: ccx.const_kind(),
493                 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()),
494             })
495         } else {
496             ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
497                 span,
498                 opt_help: None,
499                 kind: ccx.const_kind(),
500                 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()),
501             })
502         }
503     }
504 }
505
506 #[derive(Debug)]
507 /// This op is for `&mut` borrows in the trailing expression of a constant
508 /// which uses the "enclosing scopes rule" to leak its locals into anonymous
509 /// static or const items.
510 pub struct MutBorrow(pub hir::BorrowKind);
511
512 impl<'tcx> NonConstOp<'tcx> for MutBorrow {
513     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
514         Status::Forbidden
515     }
516
517     fn importance(&self) -> DiagnosticImportance {
518         // If there were primary errors (like non-const function calls), do not emit further
519         // errors about mutable references.
520         DiagnosticImportance::Secondary
521     }
522
523     fn build_error(
524         &self,
525         ccx: &ConstCx<'_, 'tcx>,
526         span: Span,
527     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
528         match self.0 {
529             hir::BorrowKind::Raw => ccx.tcx.sess.create_err(errors::UnallowedMutableRefsRaw {
530                 span,
531                 kind: ccx.const_kind(),
532                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
533             }),
534             hir::BorrowKind::Ref => ccx.tcx.sess.create_err(errors::UnallowedMutableRefs {
535                 span,
536                 kind: ccx.const_kind(),
537                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
538             }),
539         }
540     }
541 }
542
543 #[derive(Debug)]
544 pub struct TransientMutBorrow(pub hir::BorrowKind);
545
546 impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
547     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
548         Status::Unstable(sym::const_mut_refs)
549     }
550
551     fn build_error(
552         &self,
553         ccx: &ConstCx<'_, 'tcx>,
554         span: Span,
555     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
556         let kind = ccx.const_kind();
557         match self.0 {
558             hir::BorrowKind::Raw => ccx.tcx.sess.create_feature_err(
559                 errors::TransientMutBorrowErrRaw { span, kind },
560                 sym::const_mut_refs,
561             ),
562             hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err(
563                 errors::TransientMutBorrowErr { span, kind },
564                 sym::const_mut_refs,
565             ),
566         }
567     }
568 }
569
570 #[derive(Debug)]
571 pub struct MutDeref;
572 impl<'tcx> NonConstOp<'tcx> for MutDeref {
573     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
574         Status::Unstable(sym::const_mut_refs)
575     }
576
577     fn importance(&self) -> DiagnosticImportance {
578         // Usually a side-effect of a `TransientMutBorrow` somewhere.
579         DiagnosticImportance::Secondary
580     }
581
582     fn build_error(
583         &self,
584         ccx: &ConstCx<'_, 'tcx>,
585         span: Span,
586     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
587         ccx.tcx.sess.create_feature_err(
588             errors::MutDerefErr { span, kind: ccx.const_kind() },
589             sym::const_mut_refs,
590         )
591     }
592 }
593
594 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
595 #[derive(Debug)]
596 pub struct PanicNonStr;
597 impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
598     fn build_error(
599         &self,
600         ccx: &ConstCx<'_, 'tcx>,
601         span: Span,
602     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
603         ccx.tcx.sess.create_err(errors::PanicNonStrErr { span })
604     }
605 }
606
607 /// Comparing raw pointers for equality.
608 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
609 /// allocation base addresses that are not known at compile-time.
610 #[derive(Debug)]
611 pub struct RawPtrComparison;
612 impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
613     fn build_error(
614         &self,
615         _: &ConstCx<'_, 'tcx>,
616         span: Span,
617     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
618         span_bug!(span, "raw ptr comparison should already be caught in the trait system");
619     }
620 }
621
622 #[derive(Debug)]
623 pub struct RawMutPtrDeref;
624 impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
625     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
626         Status::Unstable(sym::const_mut_refs)
627     }
628
629     fn build_error(
630         &self,
631         ccx: &ConstCx<'_, 'tcx>,
632         span: Span,
633     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
634         feature_err(
635             &ccx.tcx.sess.parse_sess,
636             sym::const_mut_refs,
637             span,
638             &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
639         )
640     }
641 }
642
643 /// Casting raw pointer or function pointer to an integer.
644 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
645 /// allocation base addresses that are not known at compile-time.
646 #[derive(Debug)]
647 pub struct RawPtrToIntCast;
648 impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
649     fn build_error(
650         &self,
651         ccx: &ConstCx<'_, 'tcx>,
652         span: Span,
653     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
654         ccx.tcx.sess.create_err(errors::RawPtrToIntErr { span })
655     }
656 }
657
658 /// An access to a (non-thread-local) `static`.
659 #[derive(Debug)]
660 pub struct StaticAccess;
661 impl<'tcx> NonConstOp<'tcx> for StaticAccess {
662     fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
663         if let hir::ConstContext::Static(_) = ccx.const_kind() {
664             Status::Allowed
665         } else {
666             Status::Forbidden
667         }
668     }
669
670     fn build_error(
671         &self,
672         ccx: &ConstCx<'_, 'tcx>,
673         span: Span,
674     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
675         ccx.tcx.sess.create_err(errors::StaticAccessErr {
676             span,
677             kind: ccx.const_kind(),
678             teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()),
679         })
680     }
681 }
682
683 /// An access to a thread-local `static`.
684 #[derive(Debug)]
685 pub struct ThreadLocalAccess;
686 impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
687     fn build_error(
688         &self,
689         ccx: &ConstCx<'_, 'tcx>,
690         span: Span,
691     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
692         ccx.tcx.sess.create_err(errors::NonConstOpErr { span })
693     }
694 }
695
696 /// Types that cannot appear in the signature or locals of a `const fn`.
697 pub mod ty {
698     use super::*;
699
700     #[derive(Debug)]
701     pub struct MutRef(pub mir::LocalKind);
702     impl<'tcx> NonConstOp<'tcx> for MutRef {
703         fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
704             Status::Unstable(sym::const_mut_refs)
705         }
706
707         fn importance(&self) -> DiagnosticImportance {
708             match self.0 {
709                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
710                 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
711                     DiagnosticImportance::Primary
712                 }
713             }
714         }
715
716         fn build_error(
717             &self,
718             ccx: &ConstCx<'_, 'tcx>,
719             span: Span,
720         ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
721             feature_err(
722                 &ccx.tcx.sess.parse_sess,
723                 sym::const_mut_refs,
724                 span,
725                 &format!("mutable references are not allowed in {}s", ccx.const_kind()),
726             )
727         }
728     }
729 }