]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_const_eval/src/transform/check_consts/ops.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_const_eval / src / transform / check_consts / ops.rs
CommitLineData
1b1a35ee
XL
1//! Concrete error types for all operations which may be invalid in a certain const context.
2
a2a8927a 3use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
1b1a35ee
XL
4use rustc_hir as hir;
5use rustc_hir::def_id::DefId;
5099ac24
FG
6use rustc_infer::infer::TyCtxtInferExt;
7use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
8use rustc_middle::mir;
9use rustc_middle::ty::print::with_no_trimmed_paths;
a2a8927a 10use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
5099ac24
FG
11use rustc_middle::ty::{
12 suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
13};
14use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
1b1a35ee
XL
15use rustc_session::parse::feature_err;
16use rustc_span::symbol::sym;
5099ac24
FG
17use rustc_span::{BytePos, Pos, Span, Symbol};
18use rustc_trait_selection::traits::SelectionContext;
1b1a35ee
XL
19
20use super::ConstCx;
5099ac24 21use crate::util::{call_kind, CallDesugaringKind, CallKind};
1b1a35ee
XL
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum Status {
25 Allowed,
26 Unstable(Symbol),
27 Forbidden,
28}
29
30#[derive(Clone, Copy)]
31pub 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.
5099ac24 40pub trait NonConstOp<'tcx>: std::fmt::Debug {
1b1a35ee 41 /// Returns an enum indicating whether this operation is allowed within the given item.
5099ac24 42 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
43 Status::Forbidden
44 }
45
46 fn importance(&self) -> DiagnosticImportance {
47 DiagnosticImportance::Primary
48 }
49
5099ac24 50 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
1b1a35ee
XL
51}
52
1b1a35ee
XL
53#[derive(Debug)]
54pub struct FloatingPointOp;
5099ac24
FG
55impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
56 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
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
5099ac24 64 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
76pub struct FnCallIndirect;
5099ac24
FG
77impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
78 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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`.
5099ac24
FG
84#[derive(Debug, Clone, Copy)]
85pub 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}
a2a8927a 92
5099ac24
FG
93impl<'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 );
a2a8927a
XL
256 }
257 }
258 }
a2a8927a 259 }
5099ac24 260 _ => {}
a2a8927a
XL
261 }
262 }
5099ac24
FG
263
264 diag_trait(err, self_ty, trait_id)
a2a8927a 265 }
5099ac24
FG
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 ));
a2a8927a
XL
300
301 err
1b1a35ee
XL
302 }
303}
304
94222f64 305/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
1b1a35ee
XL
306///
307/// Contains the name of the feature that would allow the use of this function.
308#[derive(Debug)]
309pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
310
5099ac24
FG
311impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
312 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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() {
c295e0f8 321 err.help("const-stable functions can only call other const-stable functions");
fc512014 322 } else if ccx.tcx.sess.is_nightly_build() {
1b1a35ee
XL
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)]
336pub struct FnPtrCast;
5099ac24
FG
337impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
338 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
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
5099ac24 346 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
357pub struct Generator(pub hir::GeneratorKind);
5099ac24
FG
358impl<'tcx> NonConstOp<'tcx> for Generator {
359 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
17df50a5
XL
360 if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
361 Status::Unstable(sym::const_async_blocks)
362 } else {
363 Status::Forbidden
364 }
1b1a35ee
XL
365 }
366
5099ac24 367 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee 368 let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
17df50a5
XL
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 }
1b1a35ee
XL
374 }
375}
376
377#[derive(Debug)]
378pub struct HeapAllocation;
5099ac24
FG
379impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
380 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
402pub struct InlineAsm;
5099ac24
FG
403impl<'tcx> NonConstOp<'tcx> for InlineAsm {
404 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
416pub struct LiveDrop {
417 pub dropped_at: Option<Span>,
418}
5099ac24
FG
419impl<'tcx> NonConstOp<'tcx> for LiveDrop {
420 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
5869c6ff
XL
436/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
437/// the final value of the constant.
438pub struct TransientCellBorrow;
5099ac24
FG
439impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
440 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
5869c6ff
XL
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 }
5099ac24 448 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
5869c6ff
XL
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.
1b1a35ee 462pub struct CellBorrow;
5099ac24
FG
463impl<'tcx> NonConstOp<'tcx> for CellBorrow {
464 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
5869c6ff 465 let mut err = struct_span_err!(
1b1a35ee
XL
466 ccx.tcx.sess,
467 span,
468 E0492,
5869c6ff
XL
469 "{}s cannot refer to interior mutable data",
470 ccx.const_kind(),
471 );
472 err.span_label(
473 span,
94222f64 474 "this borrow of an interior mutable value may end up in the final value",
5869c6ff
XL
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
1b1a35ee
XL
491 }
492}
493
494#[derive(Debug)]
5869c6ff
XL
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.
29967ef6
XL
498pub struct MutBorrow(pub hir::BorrowKind);
499
5099ac24
FG
500impl<'tcx> NonConstOp<'tcx> for MutBorrow {
501 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
5869c6ff
XL
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
1b1a35ee
XL
509 }
510
5099ac24 511 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
29967ef6
XL
512 let raw = match self.0 {
513 hir::BorrowKind::Raw => "raw ",
514 hir::BorrowKind::Ref => "",
515 };
516
5869c6ff
XL
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
1b1a35ee
XL
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
5869c6ff
XL
542#[derive(Debug)]
543pub struct TransientMutBorrow(pub hir::BorrowKind);
544
5099ac24
FG
545impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
546 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
5869c6ff
XL
547 Status::Unstable(sym::const_mut_refs)
548 }
549
5099ac24 550 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
5869c6ff
XL
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
1b1a35ee
XL
565#[derive(Debug)]
566pub struct MutDeref;
5099ac24
FG
567impl<'tcx> NonConstOp<'tcx> for MutDeref {
568 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
569 Status::Unstable(sym::const_mut_refs)
570 }
571
572 fn importance(&self) -> DiagnosticImportance {
5869c6ff 573 // Usually a side-effect of a `TransientMutBorrow` somewhere.
1b1a35ee
XL
574 DiagnosticImportance::Secondary
575 }
576
5099ac24 577 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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
6a06907d
XL
587/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
588#[derive(Debug)]
589pub struct PanicNonStr;
5099ac24
FG
590impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
591 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
6a06907d
XL
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
136023e0
XL
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.
1b1a35ee
XL
602#[derive(Debug)]
603pub struct RawPtrComparison;
5099ac24
FG
604impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
605 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
606 let mut err = ccx
607 .tcx
608 .sess
c295e0f8 609 .struct_span_err(span, "pointers cannot be reliably compared during const eval");
1b1a35ee
XL
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)]
3c0e092e 619pub struct RawMutPtrDeref;
5099ac24 620impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
1b1a35ee 621 fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
3c0e092e 622 Status::Unstable(sym::const_mut_refs)
1b1a35ee
XL
623 }
624
5099ac24 625 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
626 feature_err(
627 &ccx.tcx.sess.parse_sess,
3c0e092e 628 sym::const_mut_refs,
1b1a35ee 629 span,
3c0e092e 630 &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
1b1a35ee
XL
631 )
632 }
633}
634
136023e0
XL
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.
1b1a35ee
XL
638#[derive(Debug)]
639pub struct RawPtrToIntCast;
5099ac24
FG
640impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
641 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
136023e0
XL
642 let mut err = ccx
643 .tcx
644 .sess
c295e0f8 645 .struct_span_err(span, "pointers cannot be cast to integers during const eval");
136023e0
XL
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
1b1a35ee
XL
651 }
652}
653
654/// An access to a (non-thread-local) `static`.
655#[derive(Debug)]
656pub struct StaticAccess;
5099ac24
FG
657impl<'tcx> NonConstOp<'tcx> for StaticAccess {
658 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
659 if let hir::ConstContext::Static(_) = ccx.const_kind() {
660 Status::Allowed
661 } else {
662 Status::Forbidden
663 }
664 }
665
5099ac24 666 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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)]
690pub struct ThreadLocalAccess;
5099ac24
FG
691impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
692 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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
1b1a35ee
XL
703// Types that cannot appear in the signature or locals of a `const fn`.
704pub mod ty {
705 use super::*;
706
707 #[derive(Debug)]
708 pub struct MutRef(pub mir::LocalKind);
5099ac24
FG
709 impl<'tcx> NonConstOp<'tcx> for MutRef {
710 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
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
5099ac24 723 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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);
5099ac24 735 impl<'tcx> NonConstOp<'tcx> for FnPtr {
1b1a35ee
XL
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
5099ac24 745 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
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
5099ac24 753 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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;
5099ac24 765 impl<'tcx> NonConstOp<'tcx> for ImplTrait {
29967ef6
XL
766 fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
767 Status::Unstable(sym::const_impl_trait)
1b1a35ee
XL
768 }
769
5099ac24 770 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
29967ef6
XL
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 )
1b1a35ee
XL
777 }
778 }
779
780 #[derive(Debug)]
781 pub struct TraitBound(pub mir::LocalKind);
5099ac24 782 impl<'tcx> NonConstOp<'tcx> for TraitBound {
1b1a35ee
XL
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
5099ac24 792 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
cdc7bbd5
XL
793 if ccx.const_kind() != hir::ConstContext::ConstFn {
794 Status::Allowed
795 } else {
796 Status::Unstable(sym::const_fn_trait_bound)
797 }
1b1a35ee
XL
798 }
799
5099ac24 800 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
c295e0f8 801 let mut err = feature_err(
cdc7bbd5
XL
802 &ccx.tcx.sess.parse_sess,
803 sym::const_fn_trait_bound,
1b1a35ee
XL
804 span,
805 "trait bounds other than `Sized` on const fn parameters are unstable",
c295e0f8
XL
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);
5099ac24 821 impl<'tcx> NonConstOp<'tcx> for DynTrait {
c295e0f8
XL
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
5099ac24 831 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
c295e0f8
XL
832 if ccx.const_kind() != hir::ConstContext::ConstFn {
833 Status::Allowed
834 } else {
835 Status::Unstable(sym::const_fn_trait_bound)
836 }
837 }
838
5099ac24 839 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
c295e0f8
XL
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
1b1a35ee
XL
855 }
856 }
857
858 /// A trait bound with the `?const Trait` opt-out
859 #[derive(Debug)]
860 pub struct TraitBoundNotConst;
5099ac24
FG
861 impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
862 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
1b1a35ee
XL
863 Status::Unstable(sym::const_trait_bound_opt_out)
864 }
865
5099ac24 866 fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
1b1a35ee
XL
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}