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