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