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