rustc_const_eval/
errors.rs

1use std::borrow::Cow;
2use std::fmt::Write;
3
4use either::Either;
5use rustc_abi::WrappingRange;
6use rustc_errors::codes::*;
7use rustc_errors::{
8    Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic,
9};
10use rustc_hir::ConstContext;
11use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
12use rustc_middle::mir::interpret::{
13    CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo,
14    Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo,
15    UnsupportedOpInfo, ValidationErrorInfo,
16};
17use rustc_middle::ty::{self, Mutability, Ty};
18use rustc_span::{Span, Symbol};
19
20use crate::fluent_generated as fluent;
21use crate::interpret::InternKind;
22
23#[derive(Diagnostic)]
24#[diag(const_eval_dangling_ptr_in_final)]
25pub(crate) struct DanglingPtrInFinal {
26    #[primary_span]
27    pub span: Span,
28    pub kind: InternKind,
29}
30
31#[derive(Diagnostic)]
32#[diag(const_eval_nested_static_in_thread_local)]
33pub(crate) struct NestedStaticInThreadLocal {
34    #[primary_span]
35    pub span: Span,
36}
37
38#[derive(Diagnostic)]
39#[diag(const_eval_mutable_ptr_in_final)]
40pub(crate) struct MutablePtrInFinal {
41    #[primary_span]
42    pub span: Span,
43    pub kind: InternKind,
44}
45
46#[derive(Diagnostic)]
47#[diag(const_eval_unstable_in_stable_exposed)]
48pub(crate) struct UnstableInStableExposed {
49    pub gate: String,
50    #[primary_span]
51    pub span: Span,
52    #[help(const_eval_is_function_call)]
53    pub is_function_call: bool,
54    /// Need to duplicate the field so that fluent also provides it as a variable...
55    pub is_function_call2: bool,
56    #[suggestion(
57        const_eval_unstable_sugg,
58        code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
59        applicability = "has-placeholders"
60    )]
61    pub attr_span: Span,
62}
63
64#[derive(Diagnostic)]
65#[diag(const_eval_thread_local_access, code = E0625)]
66pub(crate) struct ThreadLocalAccessErr {
67    #[primary_span]
68    pub span: Span,
69}
70
71#[derive(Diagnostic)]
72#[diag(const_eval_raw_ptr_to_int)]
73#[note]
74#[note(const_eval_note2)]
75pub(crate) struct RawPtrToIntErr {
76    #[primary_span]
77    pub span: Span,
78}
79
80#[derive(Diagnostic)]
81#[diag(const_eval_raw_ptr_comparison)]
82#[note]
83pub(crate) struct RawPtrComparisonErr {
84    #[primary_span]
85    pub span: Span,
86}
87
88#[derive(Diagnostic)]
89#[diag(const_eval_panic_non_str)]
90pub(crate) struct PanicNonStrErr {
91    #[primary_span]
92    pub span: Span,
93}
94
95#[derive(Diagnostic)]
96#[diag(const_eval_max_num_nodes_in_const)]
97pub(crate) struct MaxNumNodesInConstErr {
98    #[primary_span]
99    pub span: Option<Span>,
100    pub global_const_id: String,
101}
102
103#[derive(Diagnostic)]
104#[diag(const_eval_unallowed_fn_pointer_call)]
105pub(crate) struct UnallowedFnPointerCall {
106    #[primary_span]
107    pub span: Span,
108    pub kind: ConstContext,
109}
110
111#[derive(Diagnostic)]
112#[diag(const_eval_unstable_const_fn)]
113pub(crate) struct UnstableConstFn {
114    #[primary_span]
115    pub span: Span,
116    pub def_path: String,
117}
118
119#[derive(Diagnostic)]
120#[diag(const_eval_unstable_const_trait)]
121pub(crate) struct UnstableConstTrait {
122    #[primary_span]
123    pub span: Span,
124    pub def_path: String,
125}
126
127#[derive(Diagnostic)]
128#[diag(const_eval_unstable_intrinsic)]
129pub(crate) struct UnstableIntrinsic {
130    #[primary_span]
131    pub span: Span,
132    pub name: Symbol,
133    pub feature: Symbol,
134    #[suggestion(
135        const_eval_unstable_intrinsic_suggestion,
136        code = "#![feature({feature})]\n",
137        applicability = "machine-applicable"
138    )]
139    pub suggestion: Span,
140}
141
142#[derive(Diagnostic)]
143#[diag(const_eval_unmarked_const_item_exposed)]
144#[help]
145pub(crate) struct UnmarkedConstItemExposed {
146    #[primary_span]
147    pub span: Span,
148    pub def_path: String,
149}
150
151#[derive(Diagnostic)]
152#[diag(const_eval_unmarked_intrinsic_exposed)]
153#[help]
154pub(crate) struct UnmarkedIntrinsicExposed {
155    #[primary_span]
156    pub span: Span,
157    pub def_path: String,
158}
159
160#[derive(Diagnostic)]
161#[diag(const_eval_mutable_ref_escaping, code = E0764)]
162pub(crate) struct MutableRefEscaping {
163    #[primary_span]
164    pub span: Span,
165    pub kind: ConstContext,
166    #[note(const_eval_teach_note)]
167    pub teach: bool,
168}
169
170#[derive(Diagnostic)]
171#[diag(const_eval_mutable_raw_escaping, code = E0764)]
172pub(crate) struct MutableRawEscaping {
173    #[primary_span]
174    pub span: Span,
175    pub kind: ConstContext,
176    #[note(const_eval_teach_note)]
177    pub teach: bool,
178}
179#[derive(Diagnostic)]
180#[diag(const_eval_non_const_fmt_macro_call, code = E0015)]
181pub(crate) struct NonConstFmtMacroCall {
182    #[primary_span]
183    pub span: Span,
184    pub kind: ConstContext,
185    pub non_or_conditionally: &'static str,
186}
187
188#[derive(Diagnostic)]
189#[diag(const_eval_non_const_fn_call, code = E0015)]
190pub(crate) struct NonConstFnCall {
191    #[primary_span]
192    pub span: Span,
193    pub def_path_str: String,
194    pub def_descr: &'static str,
195    pub kind: ConstContext,
196    pub non_or_conditionally: &'static str,
197}
198
199#[derive(Diagnostic)]
200#[diag(const_eval_non_const_intrinsic)]
201pub(crate) struct NonConstIntrinsic {
202    #[primary_span]
203    pub span: Span,
204    pub name: Symbol,
205    pub kind: ConstContext,
206}
207
208#[derive(Diagnostic)]
209#[diag(const_eval_unallowed_op_in_const_context)]
210pub(crate) struct UnallowedOpInConstContext {
211    #[primary_span]
212    pub span: Span,
213    pub msg: String,
214}
215
216#[derive(Diagnostic)]
217#[diag(const_eval_unallowed_heap_allocations, code = E0010)]
218pub(crate) struct UnallowedHeapAllocations {
219    #[primary_span]
220    #[label]
221    pub span: Span,
222    pub kind: ConstContext,
223    #[note(const_eval_teach_note)]
224    pub teach: bool,
225}
226
227#[derive(Diagnostic)]
228#[diag(const_eval_unallowed_inline_asm, code = E0015)]
229pub(crate) struct UnallowedInlineAsm {
230    #[primary_span]
231    pub span: Span,
232    pub kind: ConstContext,
233}
234
235#[derive(Diagnostic)]
236#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)]
237pub(crate) struct InteriorMutableRefEscaping {
238    #[primary_span]
239    #[label]
240    pub span: Span,
241    #[help]
242    pub opt_help: bool,
243    pub kind: ConstContext,
244    #[note(const_eval_teach_note)]
245    pub teach: bool,
246}
247
248#[derive(LintDiagnostic)]
249#[diag(const_eval_long_running)]
250#[note]
251pub struct LongRunning {
252    #[help]
253    pub item_span: Span,
254}
255
256#[derive(Diagnostic)]
257#[diag(const_eval_long_running)]
258pub struct LongRunningWarn {
259    #[primary_span]
260    #[label]
261    pub span: Span,
262    #[help]
263    pub item_span: Span,
264    // Used for evading `-Z deduplicate-diagnostics`.
265    pub force_duplicate: usize,
266}
267
268#[derive(Subdiagnostic)]
269#[note(const_eval_non_const_impl)]
270pub(crate) struct NonConstImplNote {
271    #[primary_span]
272    pub span: Span,
273}
274
275#[derive(Clone)]
276pub struct FrameNote {
277    pub span: Span,
278    pub times: i32,
279    pub where_: &'static str,
280    pub instance: String,
281    pub has_label: bool,
282}
283
284impl Subdiagnostic for FrameNote {
285    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
286        diag.arg("times", self.times);
287        diag.arg("where_", self.where_);
288        diag.arg("instance", self.instance);
289        let mut span: MultiSpan = self.span.into();
290        if self.has_label && !self.span.is_dummy() {
291            span.push_span_label(self.span, fluent::const_eval_frame_note_last);
292        }
293        let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
294        diag.span_note(span, msg);
295    }
296}
297
298#[derive(Subdiagnostic)]
299#[note(const_eval_raw_bytes)]
300pub struct RawBytesNote {
301    pub size: u64,
302    pub align: u64,
303    pub bytes: String,
304}
305
306// FIXME(fee1-dead) do not use stringly typed `ConstContext`
307
308#[derive(Diagnostic)]
309#[diag(const_eval_non_const_match_eq, code = E0015)]
310#[note]
311pub struct NonConstMatchEq<'tcx> {
312    #[primary_span]
313    pub span: Span,
314    pub ty: Ty<'tcx>,
315    pub kind: ConstContext,
316    pub non_or_conditionally: &'static str,
317}
318
319#[derive(Diagnostic)]
320#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)]
321pub struct NonConstForLoopIntoIter<'tcx> {
322    #[primary_span]
323    pub span: Span,
324    pub ty: Ty<'tcx>,
325    pub kind: ConstContext,
326    pub non_or_conditionally: &'static str,
327}
328
329#[derive(Diagnostic)]
330#[diag(const_eval_non_const_question_branch, code = E0015)]
331pub struct NonConstQuestionBranch<'tcx> {
332    #[primary_span]
333    pub span: Span,
334    pub ty: Ty<'tcx>,
335    pub kind: ConstContext,
336    pub non_or_conditionally: &'static str,
337}
338
339#[derive(Diagnostic)]
340#[diag(const_eval_non_const_question_from_residual, code = E0015)]
341pub struct NonConstQuestionFromResidual<'tcx> {
342    #[primary_span]
343    pub span: Span,
344    pub ty: Ty<'tcx>,
345    pub kind: ConstContext,
346    pub non_or_conditionally: &'static str,
347}
348
349#[derive(Diagnostic)]
350#[diag(const_eval_non_const_try_block_from_output, code = E0015)]
351pub struct NonConstTryBlockFromOutput<'tcx> {
352    #[primary_span]
353    pub span: Span,
354    pub ty: Ty<'tcx>,
355    pub kind: ConstContext,
356    pub non_or_conditionally: &'static str,
357}
358
359#[derive(Diagnostic)]
360#[diag(const_eval_non_const_await, code = E0015)]
361pub struct NonConstAwait<'tcx> {
362    #[primary_span]
363    pub span: Span,
364    pub ty: Ty<'tcx>,
365    pub kind: ConstContext,
366    pub non_or_conditionally: &'static str,
367}
368
369#[derive(Diagnostic)]
370#[diag(const_eval_non_const_closure, code = E0015)]
371pub struct NonConstClosure {
372    #[primary_span]
373    pub span: Span,
374    pub kind: ConstContext,
375    #[subdiagnostic]
376    pub note: Option<NonConstClosureNote>,
377    pub non_or_conditionally: &'static str,
378}
379
380#[derive(Subdiagnostic)]
381pub enum NonConstClosureNote {
382    #[note(const_eval_closure_fndef_not_const)]
383    FnDef {
384        #[primary_span]
385        span: Span,
386    },
387    #[note(const_eval_fn_ptr_call)]
388    FnPtr,
389    #[note(const_eval_closure_call)]
390    Closure,
391}
392
393#[derive(Subdiagnostic)]
394#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")]
395pub struct ConsiderDereferencing {
396    pub deref: String,
397    #[suggestion_part(code = "{deref}")]
398    pub span: Span,
399    #[suggestion_part(code = "{deref}")]
400    pub rhs_span: Span,
401}
402
403#[derive(Diagnostic)]
404#[diag(const_eval_non_const_operator, code = E0015)]
405pub struct NonConstOperator {
406    #[primary_span]
407    pub span: Span,
408    pub kind: ConstContext,
409    #[subdiagnostic]
410    pub sugg: Option<ConsiderDereferencing>,
411    pub non_or_conditionally: &'static str,
412}
413
414#[derive(Diagnostic)]
415#[diag(const_eval_non_const_deref_coercion, code = E0015)]
416#[note]
417pub struct NonConstDerefCoercion<'tcx> {
418    #[primary_span]
419    pub span: Span,
420    pub ty: Ty<'tcx>,
421    pub kind: ConstContext,
422    pub target_ty: Ty<'tcx>,
423    #[note(const_eval_target_note)]
424    pub deref_target: Option<Span>,
425    pub non_or_conditionally: &'static str,
426}
427
428#[derive(Diagnostic)]
429#[diag(const_eval_live_drop, code = E0493)]
430pub struct LiveDrop<'tcx> {
431    #[primary_span]
432    #[label]
433    pub span: Span,
434    pub kind: ConstContext,
435    pub dropped_ty: Ty<'tcx>,
436    #[label(const_eval_dropped_at_label)]
437    pub dropped_at: Span,
438}
439
440pub trait ReportErrorExt {
441    /// Returns the diagnostic message for this error.
442    fn diagnostic_message(&self) -> DiagMessage;
443    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
444
445    fn debug(self) -> String
446    where
447        Self: Sized,
448    {
449        ty::tls::with(move |tcx| {
450            let dcx = tcx.dcx();
451            let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into()));
452            let message = self.diagnostic_message();
453            self.add_args(&mut diag);
454            let s = dcx.eagerly_translate_to_string(message, diag.args.iter());
455            diag.cancel();
456            s
457        })
458    }
459}
460
461impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
462    fn diagnostic_message(&self) -> DiagMessage {
463        use UndefinedBehaviorInfo::*;
464
465        use crate::fluent_generated::*;
466        match self {
467            Ub(msg) => msg.clone().into(),
468            Custom(x) => (x.msg)(),
469            ValidationError(e) => e.diagnostic_message(),
470
471            Unreachable => const_eval_unreachable,
472            BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
473            DivisionByZero => const_eval_division_by_zero,
474            RemainderByZero => const_eval_remainder_by_zero,
475            DivisionOverflow => const_eval_division_overflow,
476            RemainderOverflow => const_eval_remainder_overflow,
477            PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
478            ArithOverflow { .. } => const_eval_overflow_arith,
479            ShiftOverflow { .. } => const_eval_overflow_shift,
480            InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
481            InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
482            UnterminatedCString(_) => const_eval_unterminated_c_string,
483            PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
484            PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
485            DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer,
486            DanglingIntPointer { .. } => const_eval_dangling_int_pointer,
487            AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
488            WriteToReadOnly(_) => const_eval_write_to_read_only,
489            DerefFunctionPointer(_) => const_eval_deref_function_pointer,
490            DerefVTablePointer(_) => const_eval_deref_vtable_pointer,
491            InvalidBool(_) => const_eval_invalid_bool,
492            InvalidChar(_) => const_eval_invalid_char,
493            InvalidTag(_) => const_eval_invalid_tag,
494            InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
495            InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
496            InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait,
497            InvalidStr(_) => const_eval_invalid_str,
498            InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
499            InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
500            DeadLocal => const_eval_dead_local,
501            ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
502            UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
503            UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
504            InvalidNichedEnumVariantWritten { .. } => {
505                const_eval_invalid_niched_enum_variant_written
506            }
507            AbiMismatchArgument { .. } => const_eval_incompatible_types,
508            AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
509        }
510    }
511
512    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
513        use UndefinedBehaviorInfo::*;
514        match self {
515            Ub(_) => {}
516            Custom(custom) => {
517                (custom.add_args)(&mut |name, value| {
518                    diag.arg(name, value);
519                });
520            }
521            ValidationError(e) => e.add_args(diag),
522
523            Unreachable
524            | DivisionByZero
525            | RemainderByZero
526            | DivisionOverflow
527            | RemainderOverflow
528            | PointerArithOverflow
529            | InvalidMeta(InvalidMetaKind::SliceTooBig)
530            | InvalidMeta(InvalidMetaKind::TooBig)
531            | InvalidUninitBytes(None)
532            | DeadLocal
533            | UninhabitedEnumVariantWritten(_)
534            | UninhabitedEnumVariantRead(_) => {}
535
536            ArithOverflow { intrinsic } => {
537                diag.arg("intrinsic", intrinsic);
538            }
539            ShiftOverflow { intrinsic, shift_amount } => {
540                diag.arg("intrinsic", intrinsic);
541                diag.arg(
542                    "shift_amount",
543                    match shift_amount {
544                        Either::Left(v) => v.to_string(),
545                        Either::Right(v) => v.to_string(),
546                    },
547                );
548            }
549            BoundsCheckFailed { len, index } => {
550                diag.arg("len", len);
551                diag.arg("index", index);
552            }
553            UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
554                diag.arg("pointer", ptr);
555            }
556            InvalidVTableTrait { expected_dyn_type, vtable_dyn_type } => {
557                diag.arg("expected_dyn_type", expected_dyn_type.to_string());
558                diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
559            }
560            PointerUseAfterFree(alloc_id, msg) => {
561                diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg));
562            }
563            PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
564                diag.arg("alloc_size", alloc_size.bytes());
565                diag.arg("pointer", {
566                    let mut out = format!("{:?}", alloc_id);
567                    if ptr_offset > 0 {
568                        write!(out, "+{:#x}", ptr_offset).unwrap();
569                    } else if ptr_offset < 0 {
570                        write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
571                    }
572                    out
573                });
574                diag.arg("inbounds_size", inbounds_size);
575                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
576                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
577                diag.arg("ptr_offset", ptr_offset);
578                diag.arg("ptr_offset_is_neg", ptr_offset < 0);
579                diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
580                diag.arg(
581                    "alloc_size_minus_ptr_offset",
582                    alloc_size.bytes().saturating_sub(ptr_offset as u64),
583                );
584                diag.arg("operation", format!("{:?}", msg));
585            }
586            DanglingIntPointer { addr, inbounds_size, msg } => {
587                if addr != 0 {
588                    diag.arg(
589                        "pointer",
590                        Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
591                    );
592                }
593
594                diag.arg("inbounds_size", inbounds_size);
595                diag.arg("inbounds_size_is_neg", inbounds_size < 0);
596                diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
597                diag.arg("operation", format!("{:?}", msg));
598            }
599            AlignmentCheckFailed(Misalignment { required, has }, msg) => {
600                diag.arg("required", required.bytes());
601                diag.arg("has", has.bytes());
602                diag.arg("msg", format!("{msg:?}"));
603            }
604            WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
605                diag.arg("allocation", alloc);
606            }
607            InvalidBool(b) => {
608                diag.arg("value", format!("{b:02x}"));
609            }
610            InvalidChar(c) => {
611                diag.arg("value", format!("{c:08x}"));
612            }
613            InvalidTag(tag) => {
614                diag.arg("tag", format!("{tag:x}"));
615            }
616            InvalidStr(err) => {
617                diag.arg("err", format!("{err}"));
618            }
619            InvalidUninitBytes(Some((alloc, info))) => {
620                diag.arg("alloc", alloc);
621                diag.arg("access", info.access);
622                diag.arg("uninit", info.bad);
623            }
624            ScalarSizeMismatch(info) => {
625                diag.arg("target_size", info.target_size);
626                diag.arg("data_size", info.data_size);
627            }
628            InvalidNichedEnumVariantWritten { enum_ty } => {
629                diag.arg("ty", enum_ty.to_string());
630            }
631            AbiMismatchArgument { caller_ty, callee_ty }
632            | AbiMismatchReturn { caller_ty, callee_ty } => {
633                diag.arg("caller_ty", caller_ty.to_string());
634                diag.arg("callee_ty", callee_ty.to_string());
635            }
636        }
637    }
638}
639
640impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
641    fn diagnostic_message(&self) -> DiagMessage {
642        use rustc_middle::mir::interpret::ValidationErrorKind::*;
643
644        use crate::fluent_generated::*;
645        match self.kind {
646            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
647                const_eval_validation_box_to_uninhabited
648            }
649            PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
650                const_eval_validation_ref_to_uninhabited
651            }
652
653            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
654            PartialPointer => const_eval_validation_partial_pointer,
655            ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
656            ConstRefToExtern => const_eval_validation_const_ref_to_extern,
657            MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
658            NullFnPtr => const_eval_validation_null_fn_ptr,
659            NeverVal => const_eval_validation_never_val,
660            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
661            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
662            OutOfRange { .. } => const_eval_validation_out_of_range,
663            UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
664            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
665            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
666            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
667            Uninit { .. } => const_eval_validation_uninit,
668            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
669            InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
670            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
671                const_eval_validation_invalid_box_slice_meta
672            }
673            InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
674                const_eval_validation_invalid_ref_slice_meta
675            }
676
677            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
678                const_eval_validation_invalid_box_meta
679            }
680            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
681                const_eval_validation_invalid_ref_meta
682            }
683            UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
684                const_eval_validation_unaligned_ref
685            }
686            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
687
688            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
689            NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
690            DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
691                const_eval_validation_dangling_box_no_provenance
692            }
693            DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
694                const_eval_validation_dangling_ref_no_provenance
695            }
696            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
697                const_eval_validation_dangling_box_out_of_bounds
698            }
699            DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
700                const_eval_validation_dangling_ref_out_of_bounds
701            }
702            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
703                const_eval_validation_dangling_box_use_after_free
704            }
705            DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
706                const_eval_validation_dangling_ref_use_after_free
707            }
708            InvalidBool { .. } => const_eval_validation_invalid_bool,
709            InvalidChar { .. } => const_eval_validation_invalid_char,
710            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
711        }
712    }
713
714    fn add_args<G: EmissionGuarantee>(self, err: &mut Diag<'_, G>) {
715        use rustc_middle::mir::interpret::ValidationErrorKind::*;
716
717        use crate::fluent_generated as fluent;
718
719        if let PointerAsInt { .. } | PartialPointer = self.kind {
720            err.help(fluent::const_eval_ptr_as_bytes_1);
721            err.help(fluent::const_eval_ptr_as_bytes_2);
722        }
723
724        let message = if let Some(path) = self.path {
725            err.dcx.eagerly_translate_to_string(
726                fluent::const_eval_validation_front_matter_invalid_value_with_path,
727                [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
728            )
729        } else {
730            err.dcx.eagerly_translate_to_string(
731                fluent::const_eval_validation_front_matter_invalid_value,
732                [].into_iter(),
733            )
734        };
735
736        err.arg("front_matter", message);
737
738        fn add_range_arg<G: EmissionGuarantee>(
739            r: WrappingRange,
740            max_hi: u128,
741            err: &mut Diag<'_, G>,
742        ) {
743            let WrappingRange { start: lo, end: hi } = r;
744            assert!(hi <= max_hi);
745            let msg = if lo > hi {
746                fluent::const_eval_range_wrapping
747            } else if lo == hi {
748                fluent::const_eval_range_singular
749            } else if lo == 0 {
750                assert!(hi < max_hi, "should not be printing if the range covers everything");
751                fluent::const_eval_range_upper
752            } else if hi == max_hi {
753                assert!(lo > 0, "should not be printing if the range covers everything");
754                fluent::const_eval_range_lower
755            } else {
756                fluent::const_eval_range
757            };
758
759            let args = [
760                ("lo".into(), DiagArgValue::Str(lo.to_string().into())),
761                ("hi".into(), DiagArgValue::Str(hi.to_string().into())),
762            ];
763            let args = args.iter().map(|(a, b)| (a, b));
764            let message = err.dcx.eagerly_translate_to_string(msg, args);
765            err.arg("in_range", message);
766        }
767
768        match self.kind {
769            PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
770                err.arg("ty", ty);
771            }
772            PointerAsInt { expected } | Uninit { expected } => {
773                let msg = match expected {
774                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
775                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
776                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
777                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
778                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
779                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
780                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
781                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
782                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
783                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
784                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
785                };
786                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
787                err.arg("expected", msg);
788            }
789            InvalidEnumTag { value }
790            | InvalidVTablePtr { value }
791            | InvalidBool { value }
792            | InvalidChar { value }
793            | InvalidFnPtr { value } => {
794                err.arg("value", value);
795            }
796            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
797                add_range_arg(range, max_value, err)
798            }
799            OutOfRange { range, max_value, value } => {
800                err.arg("value", value);
801                add_range_arg(range, max_value, err);
802            }
803            UnalignedPtr { required_bytes, found_bytes, .. } => {
804                err.arg("required_bytes", required_bytes);
805                err.arg("found_bytes", found_bytes);
806            }
807            DanglingPtrNoProvenance { pointer, .. } => {
808                err.arg("pointer", pointer);
809            }
810            InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } => {
811                err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
812                err.arg("expected_dyn_type", expected_dyn_type.to_string());
813            }
814            NullPtr { .. }
815            | ConstRefToMutable
816            | ConstRefToExtern
817            | MutableRefToImmutable
818            | NullFnPtr
819            | NeverVal
820            | UnsafeCellInImmutable
821            | InvalidMetaSliceTooLarge { .. }
822            | InvalidMetaTooLarge { .. }
823            | DanglingPtrUseAfterFree { .. }
824            | DanglingPtrOutOfBounds { .. }
825            | UninhabitedEnumVariant
826            | PartialPointer => {}
827        }
828    }
829}
830
831impl ReportErrorExt for UnsupportedOpInfo {
832    fn diagnostic_message(&self) -> DiagMessage {
833        use crate::fluent_generated::*;
834        match self {
835            UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
836            UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field,
837            UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local,
838            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
839            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
840            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
841            UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
842            UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
843        }
844    }
845
846    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
847        use UnsupportedOpInfo::*;
848
849        use crate::fluent_generated::*;
850        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
851            diag.help(const_eval_ptr_as_bytes_1);
852            diag.help(const_eval_ptr_as_bytes_2);
853        }
854        match self {
855            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
856            // be further processed by validity checking which then turns it into something nice to
857            // print. So it's not worth the effort of having diagnostics that can print the `info`.
858            UnsizedLocal
859            | UnsupportedOpInfo::ExternTypeField
860            | Unsupported(_)
861            | ReadPointerAsInt(_) => {}
862            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
863                diag.arg("ptr", ptr);
864            }
865            ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| {
866                diag.arg("did", tcx.def_path_str(did));
867            }),
868        }
869    }
870}
871
872impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> {
873    fn diagnostic_message(&self) -> DiagMessage {
874        match self {
875            InterpErrorKind::UndefinedBehavior(ub) => ub.diagnostic_message(),
876            InterpErrorKind::Unsupported(e) => e.diagnostic_message(),
877            InterpErrorKind::InvalidProgram(e) => e.diagnostic_message(),
878            InterpErrorKind::ResourceExhaustion(e) => e.diagnostic_message(),
879            InterpErrorKind::MachineStop(e) => e.diagnostic_message(),
880        }
881    }
882    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
883        match self {
884            InterpErrorKind::UndefinedBehavior(ub) => ub.add_args(diag),
885            InterpErrorKind::Unsupported(e) => e.add_args(diag),
886            InterpErrorKind::InvalidProgram(e) => e.add_args(diag),
887            InterpErrorKind::ResourceExhaustion(e) => e.add_args(diag),
888            InterpErrorKind::MachineStop(e) => e.add_args(&mut |name, value| {
889                diag.arg(name, value);
890            }),
891        }
892    }
893}
894
895impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
896    fn diagnostic_message(&self) -> DiagMessage {
897        use crate::fluent_generated::*;
898        match self {
899            InvalidProgramInfo::TooGeneric => const_eval_too_generic,
900            InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported,
901            InvalidProgramInfo::Layout(e) => e.diagnostic_message(),
902        }
903    }
904    fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
905        match self {
906            InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
907            InvalidProgramInfo::Layout(e) => {
908                // The level doesn't matter, `dummy_diag` is consumed without it being used.
909                let dummy_level = Level::Bug;
910                let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level);
911                for (name, val) in dummy_diag.args.iter() {
912                    diag.arg(name.clone(), val.clone());
913                }
914                dummy_diag.cancel();
915            }
916        }
917    }
918}
919
920impl ReportErrorExt for ResourceExhaustionInfo {
921    fn diagnostic_message(&self) -> DiagMessage {
922        use crate::fluent_generated::*;
923        match self {
924            ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
925            ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
926            ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
927            ResourceExhaustionInfo::Interrupted => const_eval_interrupted,
928        }
929    }
930    fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
931}
932
933impl rustc_errors::IntoDiagArg for InternKind {
934    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
935        DiagArgValue::Str(Cow::Borrowed(match self {
936            InternKind::Static(Mutability::Not) => "static",
937            InternKind::Static(Mutability::Mut) => "static_mut",
938            InternKind::Constant => "const",
939            InternKind::Promoted => "promoted",
940        }))
941    }
942}