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