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